Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3296409d

History | View | Annotate | Download (150 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
#include "config.h"
23
#ifndef HAVE_CLOSESOCKET
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "libavutil/random.h"
29
#include "libavutil/avstring.h"
30
#include "libavformat/avformat.h"
31
#include "libavformat/network.h"
32
#include "libavformat/os_support.h"
33
#include "libavformat/rtp.h"
34
#include "libavformat/rtsp.h"
35
#include "libavcodec/opt.h"
36
#include <stdarg.h>
37
#include <unistd.h>
38
#include <fcntl.h>
39
#include <sys/ioctl.h>
40
#ifdef HAVE_POLL_H
41
#include <poll.h>
42
#endif
43
#include <errno.h>
44
#include <sys/time.h>
45
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
46
#include <time.h>
47
#include <sys/wait.h>
48
#include <signal.h>
49
#ifdef HAVE_DLFCN_H
50
#include <dlfcn.h>
51
#endif
52

    
53
#include "cmdutils.h"
54

    
55
#undef exit
56

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

    
60
static const OptionDef options[];
61

    
62
/* maximum number of simultaneous HTTP connections */
63
#define HTTP_MAX_CONNECTIONS 2000
64

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

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

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

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

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

    
96
#define IOBUFFER_INIT_SIZE 8192
97

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

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

    
104
typedef struct {
105
    int64_t count1, count2;
106
    int64_t time1, time2;
107
} DataRateData;
108

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

    
154
    /* RTSP state specific */
155
    uint8_t *pb_buffer; /* XXX: use that in all the code */
156
    ByteIOContext *pb;
157
    int seq; /* RTSP sequence number */
158

    
159
    /* RTP state specific */
160
    enum RTSPProtocol rtp_protocol;
161
    char session_id[32]; /* session id */
162
    AVFormatContext *rtp_ctx[MAX_STREAMS];
163

    
164
    /* RTP/UDP specific */
165
    URLContext *rtp_handles[MAX_STREAMS];
166

    
167
    /* RTP/TCP specific */
168
    struct HTTPContext *rtsp_c;
169
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170
} HTTPContext;
171

    
172
/* each generated stream is described here */
173
enum StreamType {
174
    STREAM_TYPE_LIVE,
175
    STREAM_TYPE_STATUS,
176
    STREAM_TYPE_REDIRECT,
177
};
178

    
179
enum IPAddressAction {
180
    IP_ALLOW = 1,
181
    IP_DENY,
182
};
183

    
184
typedef struct IPAddressACL {
185
    struct IPAddressACL *next;
186
    enum IPAddressAction action;
187
    /* These are in host order */
188
    struct in_addr first;
189
    struct in_addr last;
190
} IPAddressACL;
191

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

    
228
    /* feed specific */
229
    int feed_opened;     /* true if someone is writing to the feed */
230
    int is_feed;         /* true if it is a feed */
231
    int readonly;        /* True if writing is prohibited to the file */
232
    int conns_served;
233
    int64_t bytes_served;
234
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
235
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
236
    int64_t feed_size;          /* current size of feed */
237
    struct FFStream *next_feed;
238
} FFStream;
239

    
240
typedef struct FeedData {
241
    long long data_count;
242
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
243
} FeedData;
244

    
245
static struct sockaddr_in my_http_addr;
246
static struct sockaddr_in my_rtsp_addr;
247

    
248
static char logfilename[1024];
249
static HTTPContext *first_http_ctx;
250
static FFStream *first_feed;   /* contains only feeds */
251
static FFStream *first_stream; /* contains all streams, including feeds */
252

    
253
static void new_connection(int server_fd, int is_rtsp);
254
static void close_connection(HTTPContext *c);
255

    
256
/* HTTP handling */
257
static int handle_connection(HTTPContext *c);
258
static int http_parse_request(HTTPContext *c);
259
static int http_send_data(HTTPContext *c);
260
static void compute_status(HTTPContext *c);
261
static int open_input_stream(HTTPContext *c, const char *info);
262
static int http_start_receive_data(HTTPContext *c);
263
static int http_receive_data(HTTPContext *c);
264

    
265
/* RTSP handling */
266
static int rtsp_parse_request(HTTPContext *c);
267
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
268
static void rtsp_cmd_options(HTTPContext *c, const char *url);
269
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
270
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
271
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
272
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
273

    
274
/* SDP handling */
275
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
276
                                   struct in_addr my_ip);
277

    
278
/* RTP handling */
279
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
280
                                       FFStream *stream, const char *session_id,
281
                                       enum RTSPProtocol rtp_protocol);
282
static int rtp_new_av_stream(HTTPContext *c,
283
                             int stream_index, struct sockaddr_in *dest_addr,
284
                             HTTPContext *rtsp_c);
285

    
286
static const char *my_program_name;
287
static const char *my_program_dir;
288

    
289
static const char *config_filename;
290
static int ffserver_debug;
291
static int ffserver_daemon;
292
static int no_launch;
293
static int need_to_start_children;
294

    
295
static int nb_max_connections;
296
static int nb_connections;
297

    
298
static uint64_t max_bandwidth;
299
static uint64_t current_bandwidth;
300

    
301
static int64_t cur_time;           // Making this global saves on passing it around everywhere
302

    
303
static AVRandomState random_state;
304

    
305
static FILE *logfile = NULL;
306

    
307
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
308
{
309
    va_list ap;
310
    va_start(ap, fmt);
311

    
312
    if (logfile) {
313
        vfprintf(logfile, fmt, ap);
314
        fflush(logfile);
315
    }
316
    va_end(ap);
317
}
318

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

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

    
333
static void log_connection(HTTPContext *c)
334
{
335
    char buf2[32];
336

    
337
    if (c->suppress_log)
338
        return;
339

    
340
    http_log("%s - - [%s] \"%s %s %s\" %d %"PRId64"\n",
341
             inet_ntoa(c->from_addr.sin_addr),
342
             ctime1(buf2), c->method, c->url,
343
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
344
}
345

    
346
static void update_datarate(DataRateData *drd, int64_t count)
347
{
348
    if (!drd->time1 && !drd->count1) {
349
        drd->time1 = drd->time2 = cur_time;
350
        drd->count1 = drd->count2 = count;
351
    } else if (cur_time - drd->time2 > 5000) {
352
        drd->time1 = drd->time2;
353
        drd->count1 = drd->count2;
354
        drd->time2 = cur_time;
355
        drd->count2 = count;
356
    }
357
}
358

    
359
/* In bytes per second */
360
static int compute_datarate(DataRateData *drd, int64_t count)
361
{
362
    if (cur_time == drd->time1)
363
        return 0;
364

    
365
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
366
}
367

    
368

    
369
static void start_children(FFStream *feed)
370
{
371
    if (no_launch)
372
        return;
373

    
374
    for (; feed; feed = feed->next) {
375
        if (feed->child_argv && !feed->pid) {
376
            feed->pid_start = time(0);
377

    
378
            feed->pid = fork();
379

    
380
            if (feed->pid < 0) {
381
                http_log("Unable to create children\n");
382
                exit(1);
383
            }
384
            if (!feed->pid) {
385
                /* In child */
386
                char pathname[1024];
387
                char *slash;
388
                int i;
389

    
390
                for (i = 3; i < 256; i++)
391
                    close(i);
392

    
393
                if (!ffserver_debug) {
394
                    i = open("/dev/null", O_RDWR);
395
                    if (i != -1) {
396
                        dup2(i, 0);
397
                        dup2(i, 1);
398
                        dup2(i, 2);
399
                        close(i);
400
                    }
401
                }
402

    
403
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
404

    
405
                slash = strrchr(pathname, '/');
406
                if (!slash)
407
                    slash = pathname;
408
                else
409
                    slash++;
410
                strcpy(slash, "ffmpeg");
411

    
412
                /* This is needed to make relative pathnames work */
413
                chdir(my_program_dir);
414

    
415
                signal(SIGPIPE, SIG_DFL);
416

    
417
                execvp(pathname, feed->child_argv);
418

    
419
                _exit(1);
420
            }
421
        }
422
    }
423
}
424

    
425
/* open a listening socket */
426
static int socket_open_listen(struct sockaddr_in *my_addr)
427
{
428
    int server_fd, tmp;
429

    
430
    server_fd = socket(AF_INET,SOCK_STREAM,0);
431
    if (server_fd < 0) {
432
        perror ("socket");
433
        return -1;
434
    }
435

    
436
    tmp = 1;
437
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
438

    
439
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
440
        char bindmsg[32];
441
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
442
        perror (bindmsg);
443
        closesocket(server_fd);
444
        return -1;
445
    }
446

    
447
    if (listen (server_fd, 5) < 0) {
448
        perror ("listen");
449
        closesocket(server_fd);
450
        return -1;
451
    }
452
    ff_socket_nonblock(server_fd, 1);
453

    
454
    return server_fd;
455
}
456

    
457
/* start all multicast streams */
458
static void start_multicast(void)
459
{
460
    FFStream *stream;
461
    char session_id[32];
462
    HTTPContext *rtp_c;
463
    struct sockaddr_in dest_addr;
464
    int default_port, stream_index;
465

    
466
    default_port = 6000;
467
    for(stream = first_stream; stream != NULL; stream = stream->next) {
468
        if (stream->is_multicast) {
469
            /* open the RTP connection */
470
            snprintf(session_id, sizeof(session_id), "%08x%08x",
471
                     av_random(&random_state), av_random(&random_state));
472

    
473
            /* choose a port if none given */
474
            if (stream->multicast_port == 0) {
475
                stream->multicast_port = default_port;
476
                default_port += 100;
477
            }
478

    
479
            dest_addr.sin_family = AF_INET;
480
            dest_addr.sin_addr = stream->multicast_ip;
481
            dest_addr.sin_port = htons(stream->multicast_port);
482

    
483
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
484
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
485
            if (!rtp_c)
486
                continue;
487

    
488
            if (open_input_stream(rtp_c, "") < 0) {
489
                http_log("Could not open input stream for stream '%s'\n",
490
                         stream->filename);
491
                continue;
492
            }
493

    
494
            /* open each RTP stream */
495
            for(stream_index = 0; stream_index < stream->nb_streams;
496
                stream_index++) {
497
                dest_addr.sin_port = htons(stream->multicast_port +
498
                                           2 * stream_index);
499
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
500
                    http_log("Could not open output stream '%s/streamid=%d'\n",
501
                             stream->filename, stream_index);
502
                    exit(1);
503
                }
504
            }
505

    
506
            /* change state to send data */
507
            rtp_c->state = HTTPSTATE_SEND_DATA;
508
        }
509
    }
510
}
511

    
512
/* main loop of the http server */
513
static int http_server(void)
514
{
515
    int server_fd, ret, rtsp_server_fd, delay, delay1;
516
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
517
    HTTPContext *c, *c_next;
518

    
519
    server_fd = socket_open_listen(&my_http_addr);
520
    if (server_fd < 0)
521
        return -1;
522

    
523
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
524
    if (rtsp_server_fd < 0)
525
        return -1;
526

    
527
    http_log("ffserver started.\n");
528

    
529
    start_children(first_feed);
530

    
531
    first_http_ctx = NULL;
532
    nb_connections = 0;
533

    
534
    start_multicast();
535

    
536
    for(;;) {
537
        poll_entry = poll_table;
538
        poll_entry->fd = server_fd;
539
        poll_entry->events = POLLIN;
540
        poll_entry++;
541

    
542
        poll_entry->fd = rtsp_server_fd;
543
        poll_entry->events = POLLIN;
544
        poll_entry++;
545

    
546
        /* wait for events on each HTTP handle */
547
        c = first_http_ctx;
548
        delay = 1000;
549
        while (c != NULL) {
550
            int fd;
551
            fd = c->fd;
552
            switch(c->state) {
553
            case HTTPSTATE_SEND_HEADER:
554
            case RTSPSTATE_SEND_REPLY:
555
            case RTSPSTATE_SEND_PACKET:
556
                c->poll_entry = poll_entry;
557
                poll_entry->fd = fd;
558
                poll_entry->events = POLLOUT;
559
                poll_entry++;
560
                break;
561
            case HTTPSTATE_SEND_DATA_HEADER:
562
            case HTTPSTATE_SEND_DATA:
563
            case HTTPSTATE_SEND_DATA_TRAILER:
564
                if (!c->is_packetized) {
565
                    /* for TCP, we output as much as we can (may need to put a limit) */
566
                    c->poll_entry = poll_entry;
567
                    poll_entry->fd = fd;
568
                    poll_entry->events = POLLOUT;
569
                    poll_entry++;
570
                } else {
571
                    /* when ffserver is doing the timing, we work by
572
                       looking at which packet need to be sent every
573
                       10 ms */
574
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
575
                    if (delay1 < delay)
576
                        delay = delay1;
577
                }
578
                break;
579
            case HTTPSTATE_WAIT_REQUEST:
580
            case HTTPSTATE_RECEIVE_DATA:
581
            case HTTPSTATE_WAIT_FEED:
582
            case RTSPSTATE_WAIT_REQUEST:
583
                /* need to catch errors */
584
                c->poll_entry = poll_entry;
585
                poll_entry->fd = fd;
586
                poll_entry->events = POLLIN;/* Maybe this will work */
587
                poll_entry++;
588
                break;
589
            default:
590
                c->poll_entry = NULL;
591
                break;
592
            }
593
            c = c->next;
594
        }
595

    
596
        /* wait for an event on one connection. We poll at least every
597
           second to handle timeouts */
598
        do {
599
            ret = poll(poll_table, poll_entry - poll_table, delay);
600
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
601
                ff_neterrno() != FF_NETERROR(EINTR))
602
                return -1;
603
        } while (ret < 0);
604

    
605
        cur_time = av_gettime() / 1000;
606

    
607
        if (need_to_start_children) {
608
            need_to_start_children = 0;
609
            start_children(first_feed);
610
        }
611

    
612
        /* now handle the events */
613
        for(c = first_http_ctx; c != NULL; c = c_next) {
614
            c_next = c->next;
615
            if (handle_connection(c) < 0) {
616
                /* close and free the connection */
617
                log_connection(c);
618
                close_connection(c);
619
            }
620
        }
621

    
622
        poll_entry = poll_table;
623
        /* new HTTP connection request ? */
624
        if (poll_entry->revents & POLLIN)
625
            new_connection(server_fd, 0);
626
        poll_entry++;
627
        /* new RTSP connection request ? */
628
        if (poll_entry->revents & POLLIN)
629
            new_connection(rtsp_server_fd, 1);
630
    }
631
}
632

    
633
/* start waiting for a new HTTP/RTSP request */
634
static void start_wait_request(HTTPContext *c, int is_rtsp)
635
{
636
    c->buffer_ptr = c->buffer;
637
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
638

    
639
    if (is_rtsp) {
640
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
641
        c->state = RTSPSTATE_WAIT_REQUEST;
642
    } else {
643
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
644
        c->state = HTTPSTATE_WAIT_REQUEST;
645
    }
646
}
647

    
648
static void new_connection(int server_fd, int is_rtsp)
649
{
650
    struct sockaddr_in from_addr;
651
    int fd, len;
652
    HTTPContext *c = NULL;
653

    
654
    len = sizeof(from_addr);
655
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
656
                &len);
657
    if (fd < 0) {
658
        http_log("error during accept %s\n", strerror(errno));
659
        return;
660
    }
661
    ff_socket_nonblock(fd, 1);
662

    
663
    /* XXX: should output a warning page when coming
664
       close to the connection limit */
665
    if (nb_connections >= nb_max_connections)
666
        goto fail;
667

    
668
    /* add a new connection */
669
    c = av_mallocz(sizeof(HTTPContext));
670
    if (!c)
671
        goto fail;
672

    
673
    c->fd = fd;
674
    c->poll_entry = NULL;
675
    c->from_addr = from_addr;
676
    c->buffer_size = IOBUFFER_INIT_SIZE;
677
    c->buffer = av_malloc(c->buffer_size);
678
    if (!c->buffer)
679
        goto fail;
680

    
681
    c->next = first_http_ctx;
682
    first_http_ctx = c;
683
    nb_connections++;
684

    
685
    start_wait_request(c, is_rtsp);
686

    
687
    return;
688

    
689
 fail:
690
    if (c) {
691
        av_free(c->buffer);
692
        av_free(c);
693
    }
694
    closesocket(fd);
695
}
696

    
697
static void close_connection(HTTPContext *c)
698
{
699
    HTTPContext **cp, *c1;
700
    int i, nb_streams;
701
    AVFormatContext *ctx;
702
    URLContext *h;
703
    AVStream *st;
704

    
705
    /* remove connection from list */
706
    cp = &first_http_ctx;
707
    while ((*cp) != NULL) {
708
        c1 = *cp;
709
        if (c1 == c)
710
            *cp = c->next;
711
        else
712
            cp = &c1->next;
713
    }
714

    
715
    /* remove references, if any (XXX: do it faster) */
716
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
717
        if (c1->rtsp_c == c)
718
            c1->rtsp_c = NULL;
719
    }
720

    
721
    /* remove connection associated resources */
722
    if (c->fd >= 0)
723
        closesocket(c->fd);
724
    if (c->fmt_in) {
725
        /* close each frame parser */
726
        for(i=0;i<c->fmt_in->nb_streams;i++) {
727
            st = c->fmt_in->streams[i];
728
            if (st->codec->codec)
729
                avcodec_close(st->codec);
730
        }
731
        av_close_input_file(c->fmt_in);
732
    }
733

    
734
    /* free RTP output streams if any */
735
    nb_streams = 0;
736
    if (c->stream)
737
        nb_streams = c->stream->nb_streams;
738

    
739
    for(i=0;i<nb_streams;i++) {
740
        ctx = c->rtp_ctx[i];
741
        if (ctx) {
742
            av_write_trailer(ctx);
743
            av_free(ctx);
744
        }
745
        h = c->rtp_handles[i];
746
        if (h)
747
            url_close(h);
748
    }
749

    
750
    ctx = &c->fmt_ctx;
751

    
752
    if (!c->last_packet_sent) {
753
        if (ctx->oformat) {
754
            /* prepare header */
755
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
756
                av_write_trailer(ctx);
757
                av_freep(&c->pb_buffer);
758
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
759
            }
760
        }
761
    }
762

    
763
    for(i=0; i<ctx->nb_streams; i++)
764
        av_free(ctx->streams[i]);
765

    
766
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
767
        current_bandwidth -= c->stream->bandwidth;
768

    
769
    /* signal that there is no feed if we are the feeder socket */
770
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
771
        c->stream->feed_opened = 0;
772
        close(c->feed_fd);
773
    }
774

    
775
    av_freep(&c->pb_buffer);
776
    av_freep(&c->packet_buffer);
777
    av_free(c->buffer);
778
    av_free(c);
779
    nb_connections--;
780
}
781

    
782
static int handle_connection(HTTPContext *c)
783
{
784
    int len, ret;
785

    
786
    switch(c->state) {
787
    case HTTPSTATE_WAIT_REQUEST:
788
    case RTSPSTATE_WAIT_REQUEST:
789
        /* timeout ? */
790
        if ((c->timeout - cur_time) < 0)
791
            return -1;
792
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
793
            return -1;
794

    
795
        /* no need to read if no events */
796
        if (!(c->poll_entry->revents & POLLIN))
797
            return 0;
798
        /* read the data */
799
    read_loop:
800
        len = recv(c->fd, c->buffer_ptr, 1, 0);
801
        if (len < 0) {
802
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
803
                ff_neterrno() != FF_NETERROR(EINTR))
804
                return -1;
805
        } else if (len == 0) {
806
            return -1;
807
        } else {
808
            /* search for end of request. */
809
            uint8_t *ptr;
810
            c->buffer_ptr += len;
811
            ptr = c->buffer_ptr;
812
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
813
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
814
                /* request found : parse it and reply */
815
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
816
                    ret = http_parse_request(c);
817
                } else {
818
                    ret = rtsp_parse_request(c);
819
                }
820
                if (ret < 0)
821
                    return -1;
822
            } else if (ptr >= c->buffer_end) {
823
                /* request too long: cannot do anything */
824
                return -1;
825
            } else goto read_loop;
826
        }
827
        break;
828

    
829
    case HTTPSTATE_SEND_HEADER:
830
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
831
            return -1;
832

    
833
        /* no need to write if no events */
834
        if (!(c->poll_entry->revents & POLLOUT))
835
            return 0;
836
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
837
        if (len < 0) {
838
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
839
                ff_neterrno() != FF_NETERROR(EINTR)) {
840
                /* error : close connection */
841
                av_freep(&c->pb_buffer);
842
                return -1;
843
            }
844
        } else {
845
            c->buffer_ptr += len;
846
            if (c->stream)
847
                c->stream->bytes_served += len;
848
            c->data_count += len;
849
            if (c->buffer_ptr >= c->buffer_end) {
850
                av_freep(&c->pb_buffer);
851
                /* if error, exit */
852
                if (c->http_error)
853
                    return -1;
854
                /* all the buffer was sent : synchronize to the incoming stream */
855
                c->state = HTTPSTATE_SEND_DATA_HEADER;
856
                c->buffer_ptr = c->buffer_end = c->buffer;
857
            }
858
        }
859
        break;
860

    
861
    case HTTPSTATE_SEND_DATA:
862
    case HTTPSTATE_SEND_DATA_HEADER:
863
    case HTTPSTATE_SEND_DATA_TRAILER:
864
        /* for packetized output, we consider we can always write (the
865
           input streams sets the speed). It may be better to verify
866
           that we do not rely too much on the kernel queues */
867
        if (!c->is_packetized) {
868
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
869
                return -1;
870

    
871
            /* no need to read if no events */
872
            if (!(c->poll_entry->revents & POLLOUT))
873
                return 0;
874
        }
875
        if (http_send_data(c) < 0)
876
            return -1;
877
        /* close connection if trailer sent */
878
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
879
            return -1;
880
        break;
881
    case HTTPSTATE_RECEIVE_DATA:
882
        /* no need to read if no events */
883
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
884
            return -1;
885
        if (!(c->poll_entry->revents & POLLIN))
886
            return 0;
887
        if (http_receive_data(c) < 0)
888
            return -1;
889
        break;
890
    case HTTPSTATE_WAIT_FEED:
891
        /* no need to read if no events */
892
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
893
            return -1;
894

    
895
        /* nothing to do, we'll be waken up by incoming feed packets */
896
        break;
897

    
898
    case RTSPSTATE_SEND_REPLY:
899
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
900
            av_freep(&c->pb_buffer);
901
            return -1;
902
        }
903
        /* no need to write if no events */
904
        if (!(c->poll_entry->revents & POLLOUT))
905
            return 0;
906
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
907
        if (len < 0) {
908
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
909
                ff_neterrno() != FF_NETERROR(EINTR)) {
910
                /* error : close connection */
911
                av_freep(&c->pb_buffer);
912
                return -1;
913
            }
914
        } else {
915
            c->buffer_ptr += len;
916
            c->data_count += len;
917
            if (c->buffer_ptr >= c->buffer_end) {
918
                /* all the buffer was sent : wait for a new request */
919
                av_freep(&c->pb_buffer);
920
                start_wait_request(c, 1);
921
            }
922
        }
923
        break;
924
    case RTSPSTATE_SEND_PACKET:
925
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
926
            av_freep(&c->packet_buffer);
927
            return -1;
928
        }
929
        /* no need to write if no events */
930
        if (!(c->poll_entry->revents & POLLOUT))
931
            return 0;
932
        len = send(c->fd, c->packet_buffer_ptr,
933
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
934
        if (len < 0) {
935
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
936
                ff_neterrno() != FF_NETERROR(EINTR)) {
937
                /* error : close connection */
938
                av_freep(&c->packet_buffer);
939
                return -1;
940
            }
941
        } else {
942
            c->packet_buffer_ptr += len;
943
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
944
                /* all the buffer was sent : wait for a new request */
945
                av_freep(&c->packet_buffer);
946
                c->state = RTSPSTATE_WAIT_REQUEST;
947
            }
948
        }
949
        break;
950
    case HTTPSTATE_READY:
951
        /* nothing to do */
952
        break;
953
    default:
954
        return -1;
955
    }
956
    return 0;
957
}
958

    
959
static int extract_rates(char *rates, int ratelen, const char *request)
960
{
961
    const char *p;
962

    
963
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
964
        if (strncasecmp(p, "Pragma:", 7) == 0) {
965
            const char *q = p + 7;
966

    
967
            while (*q && *q != '\n' && isspace(*q))
968
                q++;
969

    
970
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
971
                int stream_no;
972
                int rate_no;
973

    
974
                q += 20;
975

    
976
                memset(rates, 0xff, ratelen);
977

    
978
                while (1) {
979
                    while (*q && *q != '\n' && *q != ':')
980
                        q++;
981

    
982
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
983
                        break;
984

    
985
                    stream_no--;
986
                    if (stream_no < ratelen && stream_no >= 0)
987
                        rates[stream_no] = rate_no;
988

    
989
                    while (*q && *q != '\n' && !isspace(*q))
990
                        q++;
991
                }
992

    
993
                return 1;
994
            }
995
        }
996
        p = strchr(p, '\n');
997
        if (!p)
998
            break;
999

    
1000
        p++;
1001
    }
1002

    
1003
    return 0;
1004
}
1005

    
1006
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1007
{
1008
    int i;
1009
    int best_bitrate = 100000000;
1010
    int best = -1;
1011

    
1012
    for (i = 0; i < feed->nb_streams; i++) {
1013
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1014

    
1015
        if (feed_codec->codec_id != codec->codec_id ||
1016
            feed_codec->sample_rate != codec->sample_rate ||
1017
            feed_codec->width != codec->width ||
1018
            feed_codec->height != codec->height)
1019
            continue;
1020

    
1021
        /* Potential stream */
1022

    
1023
        /* We want the fastest stream less than bit_rate, or the slowest
1024
         * faster than bit_rate
1025
         */
1026

    
1027
        if (feed_codec->bit_rate <= bit_rate) {
1028
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1029
                best_bitrate = feed_codec->bit_rate;
1030
                best = i;
1031
            }
1032
        } else {
1033
            if (feed_codec->bit_rate < best_bitrate) {
1034
                best_bitrate = feed_codec->bit_rate;
1035
                best = i;
1036
            }
1037
        }
1038
    }
1039

    
1040
    return best;
1041
}
1042

    
1043
static int modify_current_stream(HTTPContext *c, char *rates)
1044
{
1045
    int i;
1046
    FFStream *req = c->stream;
1047
    int action_required = 0;
1048

    
1049
    /* Not much we can do for a feed */
1050
    if (!req->feed)
1051
        return 0;
1052

    
1053
    for (i = 0; i < req->nb_streams; i++) {
1054
        AVCodecContext *codec = req->streams[i]->codec;
1055

    
1056
        switch(rates[i]) {
1057
            case 0:
1058
                c->switch_feed_streams[i] = req->feed_streams[i];
1059
                break;
1060
            case 1:
1061
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1062
                break;
1063
            case 2:
1064
                /* Wants off or slow */
1065
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1066
#ifdef WANTS_OFF
1067
                /* This doesn't work well when it turns off the only stream! */
1068
                c->switch_feed_streams[i] = -2;
1069
                c->feed_streams[i] = -2;
1070
#endif
1071
                break;
1072
        }
1073

    
1074
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1075
            action_required = 1;
1076
    }
1077

    
1078
    return action_required;
1079
}
1080

    
1081

    
1082
static void do_switch_stream(HTTPContext *c, int i)
1083
{
1084
    if (c->switch_feed_streams[i] >= 0) {
1085
#ifdef PHILIP
1086
        c->feed_streams[i] = c->switch_feed_streams[i];
1087
#endif
1088

    
1089
        /* Now update the stream */
1090
    }
1091
    c->switch_feed_streams[i] = -1;
1092
}
1093

    
1094
/* XXX: factorize in utils.c ? */
1095
/* XXX: take care with different space meaning */
1096
static void skip_spaces(const char **pp)
1097
{
1098
    const char *p;
1099
    p = *pp;
1100
    while (*p == ' ' || *p == '\t')
1101
        p++;
1102
    *pp = p;
1103
}
1104

    
1105
static void get_word(char *buf, int buf_size, const char **pp)
1106
{
1107
    const char *p;
1108
    char *q;
1109

    
1110
    p = *pp;
1111
    skip_spaces(&p);
1112
    q = buf;
1113
    while (!isspace(*p) && *p != '\0') {
1114
        if ((q - buf) < buf_size - 1)
1115
            *q++ = *p;
1116
        p++;
1117
    }
1118
    if (buf_size > 0)
1119
        *q = '\0';
1120
    *pp = p;
1121
}
1122

    
1123
static int validate_acl(FFStream *stream, HTTPContext *c)
1124
{
1125
    enum IPAddressAction last_action = IP_DENY;
1126
    IPAddressACL *acl;
1127
    struct in_addr *src = &c->from_addr.sin_addr;
1128
    unsigned long src_addr = src->s_addr;
1129

    
1130
    for (acl = stream->acl; acl; acl = acl->next) {
1131
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1132
            return (acl->action == IP_ALLOW) ? 1 : 0;
1133
        last_action = acl->action;
1134
    }
1135

    
1136
    /* Nothing matched, so return not the last action */
1137
    return (last_action == IP_DENY) ? 1 : 0;
1138
}
1139

    
1140
/* compute the real filename of a file by matching it without its
1141
   extensions to all the stream filenames */
1142
static void compute_real_filename(char *filename, int max_size)
1143
{
1144
    char file1[1024];
1145
    char file2[1024];
1146
    char *p;
1147
    FFStream *stream;
1148

    
1149
    /* compute filename by matching without the file extensions */
1150
    av_strlcpy(file1, filename, sizeof(file1));
1151
    p = strrchr(file1, '.');
1152
    if (p)
1153
        *p = '\0';
1154
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1155
        av_strlcpy(file2, stream->filename, sizeof(file2));
1156
        p = strrchr(file2, '.');
1157
        if (p)
1158
            *p = '\0';
1159
        if (!strcmp(file1, file2)) {
1160
            av_strlcpy(filename, stream->filename, max_size);
1161
            break;
1162
        }
1163
    }
1164
}
1165

    
1166
enum RedirType {
1167
    REDIR_NONE,
1168
    REDIR_ASX,
1169
    REDIR_RAM,
1170
    REDIR_ASF,
1171
    REDIR_RTSP,
1172
    REDIR_SDP,
1173
};
1174

    
1175
/* parse http request and prepare header */
1176
static int http_parse_request(HTTPContext *c)
1177
{
1178
    char *p;
1179
    enum RedirType redir_type;
1180
    char cmd[32];
1181
    char info[1024], filename[1024];
1182
    char url[1024], *q;
1183
    char protocol[32];
1184
    char msg[1024];
1185
    const char *mime_type;
1186
    FFStream *stream;
1187
    int i;
1188
    char ratebuf[32];
1189
    char *useragent = 0;
1190

    
1191
    p = c->buffer;
1192
    get_word(cmd, sizeof(cmd), (const char **)&p);
1193
    av_strlcpy(c->method, cmd, sizeof(c->method));
1194

    
1195
    if (!strcmp(cmd, "GET"))
1196
        c->post = 0;
1197
    else if (!strcmp(cmd, "POST"))
1198
        c->post = 1;
1199
    else
1200
        return -1;
1201

    
1202
    get_word(url, sizeof(url), (const char **)&p);
1203
    av_strlcpy(c->url, url, sizeof(c->url));
1204

    
1205
    get_word(protocol, sizeof(protocol), (const char **)&p);
1206
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1207
        return -1;
1208

    
1209
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1210

    
1211
    if (ffserver_debug)
1212
        http_log("New connection: %s %s\n", cmd, url);
1213

    
1214
    /* find the filename and the optional info string in the request */
1215
    p = strchr(url, '?');
1216
    if (p) {
1217
        av_strlcpy(info, p, sizeof(info));
1218
        *p = '\0';
1219
    } else
1220
        info[0] = '\0';
1221

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

    
1224
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1225
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1226
            useragent = p + 11;
1227
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1228
                useragent++;
1229
            break;
1230
        }
1231
        p = strchr(p, '\n');
1232
        if (!p)
1233
            break;
1234

    
1235
        p++;
1236
    }
1237

    
1238
    redir_type = REDIR_NONE;
1239
    if (match_ext(filename, "asx")) {
1240
        redir_type = REDIR_ASX;
1241
        filename[strlen(filename)-1] = 'f';
1242
    } else if (match_ext(filename, "asf") &&
1243
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1244
        /* if this isn't WMP or lookalike, return the redirector file */
1245
        redir_type = REDIR_ASF;
1246
    } else if (match_ext(filename, "rpm,ram")) {
1247
        redir_type = REDIR_RAM;
1248
        strcpy(filename + strlen(filename)-2, "m");
1249
    } else if (match_ext(filename, "rtsp")) {
1250
        redir_type = REDIR_RTSP;
1251
        compute_real_filename(filename, sizeof(filename) - 1);
1252
    } else if (match_ext(filename, "sdp")) {
1253
        redir_type = REDIR_SDP;
1254
        compute_real_filename(filename, sizeof(filename) - 1);
1255
    }
1256

    
1257
    // "redirect" / request to index.html
1258
    if (!strlen(filename))
1259
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1260

    
1261
    stream = first_stream;
1262
    while (stream != NULL) {
1263
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1264
            break;
1265
        stream = stream->next;
1266
    }
1267
    if (stream == NULL) {
1268
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1269
        goto send_error;
1270
    }
1271

    
1272
    c->stream = stream;
1273
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1274
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1275

    
1276
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1277
        c->http_error = 301;
1278
        q = c->buffer;
1279
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1280
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1281
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1282
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1283
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1284
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1285
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1286

    
1287
        /* prepare output buffer */
1288
        c->buffer_ptr = c->buffer;
1289
        c->buffer_end = q;
1290
        c->state = HTTPSTATE_SEND_HEADER;
1291
        return 0;
1292
    }
1293

    
1294
    /* If this is WMP, get the rate information */
1295
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1296
        if (modify_current_stream(c, ratebuf)) {
1297
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1298
                if (c->switch_feed_streams[i] >= 0)
1299
                    do_switch_stream(c, i);
1300
            }
1301
        }
1302
    }
1303

    
1304
    /* If already streaming this feed, do not let start another feeder. */
1305
    if (stream->feed_opened) {
1306
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1307
        goto send_error;
1308
    }
1309

    
1310
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1311
        current_bandwidth += stream->bandwidth;
1312

    
1313
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1314
        c->http_error = 200;
1315
        q = c->buffer;
1316
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
1322
            current_bandwidth, max_bandwidth);
1323
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1324

    
1325
        /* prepare output buffer */
1326
        c->buffer_ptr = c->buffer;
1327
        c->buffer_end = q;
1328
        c->state = HTTPSTATE_SEND_HEADER;
1329
        return 0;
1330
    }
1331

    
1332
    if (redir_type != REDIR_NONE) {
1333
        char *hostinfo = 0;
1334

    
1335
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1336
            if (strncasecmp(p, "Host:", 5) == 0) {
1337
                hostinfo = p + 5;
1338
                break;
1339
            }
1340
            p = strchr(p, '\n');
1341
            if (!p)
1342
                break;
1343

    
1344
            p++;
1345
        }
1346

    
1347
        if (hostinfo) {
1348
            char *eoh;
1349
            char hostbuf[260];
1350

    
1351
            while (isspace(*hostinfo))
1352
                hostinfo++;
1353

    
1354
            eoh = strchr(hostinfo, '\n');
1355
            if (eoh) {
1356
                if (eoh[-1] == '\r')
1357
                    eoh--;
1358

    
1359
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1360
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1361
                    hostbuf[eoh - hostinfo] = 0;
1362

    
1363
                    c->http_error = 200;
1364
                    q = c->buffer;
1365
                    switch(redir_type) {
1366
                    case REDIR_ASX:
1367
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
1368
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1369
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1370
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
1371
                        //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
1372
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1373
                                hostbuf, filename, info);
1374
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
1375
                        break;
1376
                    case REDIR_RAM:
1377
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
1378
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
1379
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1380
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
1381
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
1382
                                hostbuf, filename, info);
1383
                        break;
1384
                    case REDIR_ASF:
1385
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
1386
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1387
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1388
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
1389
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
1390
                                hostbuf, filename, info);
1391
                        break;
1392
                    case REDIR_RTSP:
1393
                        {
1394
                            char hostname[256], *p;
1395
                            /* extract only hostname */
1396
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1397
                            p = strrchr(hostname, ':');
1398
                            if (p)
1399
                                *p = '\0';
1400
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1401
                            /* XXX: incorrect mime type ? */
1402
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
1403
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1404
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
1405
                                         hostname, ntohs(my_rtsp_addr.sin_port),
1406
                                         filename);
1407
                        }
1408
                        break;
1409
                    case REDIR_SDP:
1410
                        {
1411
                            uint8_t *sdp_data;
1412
                            int sdp_data_size, len;
1413
                            struct sockaddr_in my_addr;
1414

    
1415
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1416
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1417
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1418

    
1419
                            len = sizeof(my_addr);
1420
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1421

    
1422
                            /* XXX: should use a dynamic buffer */
1423
                            sdp_data_size = prepare_sdp_description(stream,
1424
                                                                    &sdp_data,
1425
                                                                    my_addr.sin_addr);
1426
                            if (sdp_data_size > 0) {
1427
                                memcpy(q, sdp_data, sdp_data_size);
1428
                                q += sdp_data_size;
1429
                                *q = '\0';
1430
                                av_free(sdp_data);
1431
                            }
1432
                        }
1433
                        break;
1434
                    default:
1435
                        abort();
1436
                        break;
1437
                    }
1438

    
1439
                    /* prepare output buffer */
1440
                    c->buffer_ptr = c->buffer;
1441
                    c->buffer_end = q;
1442
                    c->state = HTTPSTATE_SEND_HEADER;
1443
                    return 0;
1444
                }
1445
            }
1446
        }
1447

    
1448
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1449
        goto send_error;
1450
    }
1451

    
1452
    stream->conns_served++;
1453

    
1454
    /* XXX: add there authenticate and IP match */
1455

    
1456
    if (c->post) {
1457
        /* if post, it means a feed is being sent */
1458
        if (!stream->is_feed) {
1459
            /* However it might be a status report from WMP! Lets log the data
1460
             * as it might come in handy one day
1461
             */
1462
            char *logline = 0;
1463
            int client_id = 0;
1464

    
1465
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1466
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1467
                    logline = p;
1468
                    break;
1469
                }
1470
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1471
                    client_id = strtol(p + 18, 0, 10);
1472
                p = strchr(p, '\n');
1473
                if (!p)
1474
                    break;
1475

    
1476
                p++;
1477
            }
1478

    
1479
            if (logline) {
1480
                char *eol = strchr(logline, '\n');
1481

    
1482
                logline += 17;
1483

    
1484
                if (eol) {
1485
                    if (eol[-1] == '\r')
1486
                        eol--;
1487
                    http_log("%.*s\n", (int) (eol - logline), logline);
1488
                    c->suppress_log = 1;
1489
                }
1490
            }
1491

    
1492
#ifdef DEBUG_WMP
1493
            http_log("\nGot request:\n%s\n", c->buffer);
1494
#endif
1495

    
1496
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1497
                HTTPContext *wmpc;
1498

    
1499
                /* Now we have to find the client_id */
1500
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1501
                    if (wmpc->wmp_client_id == client_id)
1502
                        break;
1503
                }
1504

    
1505
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1506
                    wmpc->switch_pending = 1;
1507
            }
1508

    
1509
            snprintf(msg, sizeof(msg), "POST command not handled");
1510
            c->stream = 0;
1511
            goto send_error;
1512
        }
1513
        if (http_start_receive_data(c) < 0) {
1514
            snprintf(msg, sizeof(msg), "could not open feed");
1515
            goto send_error;
1516
        }
1517
        c->http_error = 0;
1518
        c->state = HTTPSTATE_RECEIVE_DATA;
1519
        return 0;
1520
    }
1521

    
1522
#ifdef DEBUG_WMP
1523
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1524
        http_log("\nGot request:\n%s\n", c->buffer);
1525
#endif
1526

    
1527
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1528
        goto send_status;
1529

    
1530
    /* open input stream */
1531
    if (open_input_stream(c, info) < 0) {
1532
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1533
        goto send_error;
1534
    }
1535

    
1536
    /* prepare http header */
1537
    q = c->buffer;
1538
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1539
    mime_type = c->stream->fmt->mime_type;
1540
    if (!mime_type)
1541
        mime_type = "application/x-octet-stream";
1542
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1543

    
1544
    /* for asf, we need extra headers */
1545
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1546
        /* Need to allocate a client id */
1547

    
1548
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1549

    
1550
        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);
1551
    }
1552
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1553
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1554

    
1555
    /* prepare output buffer */
1556
    c->http_error = 0;
1557
    c->buffer_ptr = c->buffer;
1558
    c->buffer_end = q;
1559
    c->state = HTTPSTATE_SEND_HEADER;
1560
    return 0;
1561
 send_error:
1562
    c->http_error = 404;
1563
    q = c->buffer;
1564
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1565
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1566
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1567
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1568
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1569
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1570
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1571

    
1572
    /* prepare output buffer */
1573
    c->buffer_ptr = c->buffer;
1574
    c->buffer_end = q;
1575
    c->state = HTTPSTATE_SEND_HEADER;
1576
    return 0;
1577
 send_status:
1578
    compute_status(c);
1579
    c->http_error = 200; /* horrible : we use this value to avoid
1580
                            going to the send data state */
1581
    c->state = HTTPSTATE_SEND_HEADER;
1582
    return 0;
1583
}
1584

    
1585
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1586
{
1587
    static const char *suffix = " kMGTP";
1588
    const char *s;
1589

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

    
1592
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1593
}
1594

    
1595
static void compute_status(HTTPContext *c)
1596
{
1597
    HTTPContext *c1;
1598
    FFStream *stream;
1599
    char *p;
1600
    time_t ti;
1601
    int i, len;
1602
    ByteIOContext *pb;
1603

    
1604
    if (url_open_dyn_buf(&pb) < 0) {
1605
        /* XXX: return an error ? */
1606
        c->buffer_ptr = c->buffer;
1607
        c->buffer_end = c->buffer;
1608
        return;
1609
    }
1610

    
1611
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1612
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1613
    url_fprintf(pb, "Pragma: no-cache\r\n");
1614
    url_fprintf(pb, "\r\n");
1615

    
1616
    url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
1617
    if (c->stream->feed_filename[0])
1618
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1619
    url_fprintf(pb, "</HEAD>\n<BODY>");
1620
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1621
    /* format status */
1622
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1623
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1624
    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");
1625
    stream = first_stream;
1626
    while (stream != NULL) {
1627
        char sfilename[1024];
1628
        char *eosf;
1629

    
1630
        if (stream->feed != stream) {
1631
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1632
            eosf = sfilename + strlen(sfilename);
1633
            if (eosf - sfilename >= 4) {
1634
                if (strcmp(eosf - 4, ".asf") == 0)
1635
                    strcpy(eosf - 4, ".asx");
1636
                else if (strcmp(eosf - 3, ".rm") == 0)
1637
                    strcpy(eosf - 3, ".ram");
1638
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1639
                    /* generate a sample RTSP director if
1640
                       unicast. Generate an SDP redirector if
1641
                       multicast */
1642
                    eosf = strrchr(sfilename, '.');
1643
                    if (!eosf)
1644
                        eosf = sfilename + strlen(sfilename);
1645
                    if (stream->is_multicast)
1646
                        strcpy(eosf, ".sdp");
1647
                    else
1648
                        strcpy(eosf, ".rtsp");
1649
                }
1650
            }
1651

    
1652
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1653
                         sfilename, stream->filename);
1654
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1655
                        stream->conns_served);
1656
            fmt_bytecount(pb, stream->bytes_served);
1657
            switch(stream->stream_type) {
1658
            case STREAM_TYPE_LIVE:
1659
                {
1660
                    int audio_bit_rate = 0;
1661
                    int video_bit_rate = 0;
1662
                    const char *audio_codec_name = "";
1663
                    const char *video_codec_name = "";
1664
                    const char *audio_codec_name_extra = "";
1665
                    const char *video_codec_name_extra = "";
1666

    
1667
                    for(i=0;i<stream->nb_streams;i++) {
1668
                        AVStream *st = stream->streams[i];
1669
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1670
                        switch(st->codec->codec_type) {
1671
                        case CODEC_TYPE_AUDIO:
1672
                            audio_bit_rate += st->codec->bit_rate;
1673
                            if (codec) {
1674
                                if (*audio_codec_name)
1675
                                    audio_codec_name_extra = "...";
1676
                                audio_codec_name = codec->name;
1677
                            }
1678
                            break;
1679
                        case CODEC_TYPE_VIDEO:
1680
                            video_bit_rate += st->codec->bit_rate;
1681
                            if (codec) {
1682
                                if (*video_codec_name)
1683
                                    video_codec_name_extra = "...";
1684
                                video_codec_name = codec->name;
1685
                            }
1686
                            break;
1687
                        case CODEC_TYPE_DATA:
1688
                            video_bit_rate += st->codec->bit_rate;
1689
                            break;
1690
                        default:
1691
                            abort();
1692
                        }
1693
                    }
1694
                    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",
1695
                                 stream->fmt->name,
1696
                                 stream->bandwidth,
1697
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1698
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1699
                    if (stream->feed)
1700
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1701
                    else
1702
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1703
                    url_fprintf(pb, "\n");
1704
                }
1705
                break;
1706
            default:
1707
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1708
                break;
1709
            }
1710
        }
1711
        stream = stream->next;
1712
    }
1713
    url_fprintf(pb, "</TABLE>\n");
1714

    
1715
    stream = first_stream;
1716
    while (stream != NULL) {
1717
        if (stream->feed == stream) {
1718
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1719
            if (stream->pid) {
1720
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1721

    
1722
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1723
                {
1724
                    FILE *pid_stat;
1725
                    char ps_cmd[64];
1726

    
1727
                    /* This is somewhat linux specific I guess */
1728
                    snprintf(ps_cmd, sizeof(ps_cmd),
1729
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1730
                             stream->pid);
1731

    
1732
                    pid_stat = popen(ps_cmd, "r");
1733
                    if (pid_stat) {
1734
                        char cpuperc[10];
1735
                        char cpuused[64];
1736

    
1737
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1738
                                   cpuused) == 2) {
1739
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1740
                                         cpuperc, cpuused);
1741
                        }
1742
                        fclose(pid_stat);
1743
                    }
1744
                }
1745
#endif
1746

    
1747
                url_fprintf(pb, "<p>");
1748
            }
1749
            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");
1750

    
1751
            for (i = 0; i < stream->nb_streams; i++) {
1752
                AVStream *st = stream->streams[i];
1753
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1754
                const char *type = "unknown";
1755
                char parameters[64];
1756

    
1757
                parameters[0] = 0;
1758

    
1759
                switch(st->codec->codec_type) {
1760
                case CODEC_TYPE_AUDIO:
1761
                    type = "audio";
1762
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1763
                    break;
1764
                case CODEC_TYPE_VIDEO:
1765
                    type = "video";
1766
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1767
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1768
                    break;
1769
                default:
1770
                    abort();
1771
                }
1772
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1773
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1774
            }
1775
            url_fprintf(pb, "</table>\n");
1776

    
1777
        }
1778
        stream = stream->next;
1779
    }
1780

    
1781
#if 0
1782
    {
1783
        float avg;
1784
        AVCodecContext *enc;
1785
        char buf[1024];
1786

1787
        /* feed status */
1788
        stream = first_feed;
1789
        while (stream != NULL) {
1790
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1791
            url_fprintf(pb, "<TABLE>\n");
1792
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1793
            for(i=0;i<stream->nb_streams;i++) {
1794
                AVStream *st = stream->streams[i];
1795
                FeedData *fdata = st->priv_data;
1796
                enc = st->codec;
1797

1798
                avcodec_string(buf, sizeof(buf), enc);
1799
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1800
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1801
                    avg /= enc->frame_size;
1802
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1803
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1804
            }
1805
            url_fprintf(pb, "</TABLE>\n");
1806
            stream = stream->next_feed;
1807
        }
1808
    }
1809
#endif
1810

    
1811
    /* connection status */
1812
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1813

    
1814
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1815
                 nb_connections, nb_max_connections);
1816

    
1817
    url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
1818
                 current_bandwidth, max_bandwidth);
1819

    
1820
    url_fprintf(pb, "<TABLE>\n");
1821
    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");
1822
    c1 = first_http_ctx;
1823
    i = 0;
1824
    while (c1 != NULL) {
1825
        int bitrate;
1826
        int j;
1827

    
1828
        bitrate = 0;
1829
        if (c1->stream) {
1830
            for (j = 0; j < c1->stream->nb_streams; j++) {
1831
                if (!c1->stream->feed)
1832
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1833
                else if (c1->feed_streams[j] >= 0)
1834
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1835
            }
1836
        }
1837

    
1838
        i++;
1839
        p = inet_ntoa(c1->from_addr.sin_addr);
1840
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1841
                    i,
1842
                    c1->stream ? c1->stream->filename : "",
1843
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1844
                    p,
1845
                    c1->protocol,
1846
                    http_state[c1->state]);
1847
        fmt_bytecount(pb, bitrate);
1848
        url_fprintf(pb, "<td align=right>");
1849
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1850
        url_fprintf(pb, "<td align=right>");
1851
        fmt_bytecount(pb, c1->data_count);
1852
        url_fprintf(pb, "\n");
1853
        c1 = c1->next;
1854
    }
1855
    url_fprintf(pb, "</TABLE>\n");
1856

    
1857
    /* date */
1858
    ti = time(NULL);
1859
    p = ctime(&ti);
1860
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1861
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1862

    
1863
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1864
    c->buffer_ptr = c->pb_buffer;
1865
    c->buffer_end = c->pb_buffer + len;
1866
}
1867

    
1868
/* check if the parser needs to be opened for stream i */
1869
static void open_parser(AVFormatContext *s, int i)
1870
{
1871
    AVStream *st = s->streams[i];
1872
    AVCodec *codec;
1873

    
1874
    if (!st->codec->codec) {
1875
        codec = avcodec_find_decoder(st->codec->codec_id);
1876
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1877
            st->codec->parse_only = 1;
1878
            if (avcodec_open(st->codec, codec) < 0)
1879
                st->codec->parse_only = 0;
1880
        }
1881
    }
1882
}
1883

    
1884
static int open_input_stream(HTTPContext *c, const char *info)
1885
{
1886
    char buf[128];
1887
    char input_filename[1024];
1888
    AVFormatContext *s;
1889
    int buf_size, i, ret;
1890
    int64_t stream_pos;
1891

    
1892
    /* find file name */
1893
    if (c->stream->feed) {
1894
        strcpy(input_filename, c->stream->feed->feed_filename);
1895
        buf_size = FFM_PACKET_SIZE;
1896
        /* compute position (absolute time) */
1897
        if (find_info_tag(buf, sizeof(buf), "date", info))
1898
        {
1899
            stream_pos = parse_date(buf, 0);
1900
            if (stream_pos == INT64_MIN)
1901
                return -1;
1902
        }
1903
        else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1904
            int prebuffer = strtol(buf, 0, 10);
1905
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1906
        } else
1907
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1908
    } else {
1909
        strcpy(input_filename, c->stream->feed_filename);
1910
        buf_size = 0;
1911
        /* compute position (relative time) */
1912
        if (find_info_tag(buf, sizeof(buf), "date", info))
1913
        {
1914
            stream_pos = parse_date(buf, 1);
1915
            if (stream_pos == INT64_MIN)
1916
                return -1;
1917
        }
1918
        else
1919
            stream_pos = 0;
1920
    }
1921
    if (input_filename[0] == '\0')
1922
        return -1;
1923

    
1924
#if 0
1925
    { time_t when = stream_pos / 1000000;
1926
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1927
    }
1928
#endif
1929

    
1930
    /* open stream */
1931
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1932
                                  buf_size, c->stream->ap_in)) < 0) {
1933
        http_log("could not open %s: %d\n", input_filename, ret);
1934
        return -1;
1935
    }
1936
    s->flags |= AVFMT_FLAG_GENPTS;
1937
    c->fmt_in = s;
1938
    av_find_stream_info(c->fmt_in);
1939

    
1940
    /* open each parser */
1941
    for(i=0;i<s->nb_streams;i++)
1942
        open_parser(s, i);
1943

    
1944
    /* choose stream as clock source (we favorize video stream if
1945
       present) for packet sending */
1946
    c->pts_stream_index = 0;
1947
    for(i=0;i<c->stream->nb_streams;i++) {
1948
        if (c->pts_stream_index == 0 &&
1949
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1950
            c->pts_stream_index = i;
1951
        }
1952
    }
1953

    
1954
#if 1
1955
    if (c->fmt_in->iformat->read_seek)
1956
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1957
#endif
1958
    /* set the start time (needed for maxtime and RTP packet timing) */
1959
    c->start_time = cur_time;
1960
    c->first_pts = AV_NOPTS_VALUE;
1961
    return 0;
1962
}
1963

    
1964
/* return the server clock (in us) */
1965
static int64_t get_server_clock(HTTPContext *c)
1966
{
1967
    /* compute current pts value from system time */
1968
    return (cur_time - c->start_time) * 1000;
1969
}
1970

    
1971
/* return the estimated time at which the current packet must be sent
1972
   (in us) */
1973
static int64_t get_packet_send_clock(HTTPContext *c)
1974
{
1975
    int bytes_left, bytes_sent, frame_bytes;
1976

    
1977
    frame_bytes = c->cur_frame_bytes;
1978
    if (frame_bytes <= 0)
1979
        return c->cur_pts;
1980
    else {
1981
        bytes_left = c->buffer_end - c->buffer_ptr;
1982
        bytes_sent = frame_bytes - bytes_left;
1983
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1984
    }
1985
}
1986

    
1987

    
1988
static int http_prepare_data(HTTPContext *c)
1989
{
1990
    int i, len, ret;
1991
    AVFormatContext *ctx;
1992

    
1993
    av_freep(&c->pb_buffer);
1994
    switch(c->state) {
1995
    case HTTPSTATE_SEND_DATA_HEADER:
1996
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1997
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
1998
                   sizeof(c->fmt_ctx.author));
1999
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2000
                   sizeof(c->fmt_ctx.comment));
2001
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2002
                   sizeof(c->fmt_ctx.copyright));
2003
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2004
                   sizeof(c->fmt_ctx.title));
2005

    
2006
        /* open output stream by using specified codecs */
2007
        c->fmt_ctx.oformat = c->stream->fmt;
2008
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2009
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2010
            AVStream *st;
2011
            AVStream *src;
2012
            st = av_mallocz(sizeof(AVStream));
2013
            st->codec= avcodec_alloc_context();
2014
            c->fmt_ctx.streams[i] = st;
2015
            /* if file or feed, then just take streams from FFStream struct */
2016
            if (!c->stream->feed ||
2017
                c->stream->feed == c->stream)
2018
                src = c->stream->streams[i];
2019
            else
2020
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2021

    
2022
            *st = *src;
2023
            st->priv_data = 0;
2024
            st->codec->frame_number = 0; /* XXX: should be done in
2025
                                           AVStream, not in codec */
2026
        }
2027
        c->got_key_frame = 0;
2028

    
2029
        /* prepare header and save header data in a stream */
2030
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2031
            /* XXX: potential leak */
2032
            return -1;
2033
        }
2034
        c->fmt_ctx.pb->is_streamed = 1;
2035

    
2036
        /*
2037
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2038
         * Default value from FFmpeg
2039
         * Try to set it use configuration option
2040
         */
2041
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2042
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2043

    
2044
        av_set_parameters(&c->fmt_ctx, NULL);
2045
        if (av_write_header(&c->fmt_ctx) < 0) {
2046
            http_log("Error writing output header\n");
2047
            return -1;
2048
        }
2049

    
2050
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2051
        c->buffer_ptr = c->pb_buffer;
2052
        c->buffer_end = c->pb_buffer + len;
2053

    
2054
        c->state = HTTPSTATE_SEND_DATA;
2055
        c->last_packet_sent = 0;
2056
        break;
2057
    case HTTPSTATE_SEND_DATA:
2058
        /* find a new packet */
2059
        /* read a packet from the input stream */
2060
        if (c->stream->feed)
2061
            ffm_set_write_index(c->fmt_in,
2062
                                c->stream->feed->feed_write_index,
2063
                                c->stream->feed->feed_size);
2064

    
2065
        if (c->stream->max_time &&
2066
            c->stream->max_time + c->start_time - cur_time < 0)
2067
            /* We have timed out */
2068
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2069
        else {
2070
            AVPacket pkt;
2071
        redo:
2072
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2073
                if (c->stream->feed && c->stream->feed->feed_opened) {
2074
                    /* if coming from feed, it means we reached the end of the
2075
                       ffm file, so must wait for more data */
2076
                    c->state = HTTPSTATE_WAIT_FEED;
2077
                    return 1; /* state changed */
2078
                } else {
2079
                    if (c->stream->loop) {
2080
                        av_close_input_file(c->fmt_in);
2081
                        c->fmt_in = NULL;
2082
                        if (open_input_stream(c, "") < 0)
2083
                            goto no_loop;
2084
                        goto redo;
2085
                    } else {
2086
                    no_loop:
2087
                        /* must send trailer now because eof or error */
2088
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2089
                    }
2090
                }
2091
            } else {
2092
                int source_index = pkt.stream_index;
2093
                /* update first pts if needed */
2094
                if (c->first_pts == AV_NOPTS_VALUE) {
2095
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2096
                    c->start_time = cur_time;
2097
                }
2098
                /* send it to the appropriate stream */
2099
                if (c->stream->feed) {
2100
                    /* if coming from a feed, select the right stream */
2101
                    if (c->switch_pending) {
2102
                        c->switch_pending = 0;
2103
                        for(i=0;i<c->stream->nb_streams;i++) {
2104
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2105
                                if (pkt.flags & PKT_FLAG_KEY)
2106
                                    do_switch_stream(c, i);
2107
                            if (c->switch_feed_streams[i] >= 0)
2108
                                c->switch_pending = 1;
2109
                        }
2110
                    }
2111
                    for(i=0;i<c->stream->nb_streams;i++) {
2112
                        if (c->feed_streams[i] == pkt.stream_index) {
2113
                            AVStream *st = c->fmt_in->streams[source_index];
2114
                            pkt.stream_index = i;
2115
                            if (pkt.flags & PKT_FLAG_KEY &&
2116
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2117
                                 c->stream->nb_streams == 1))
2118
                                c->got_key_frame = 1;
2119
                            if (!c->stream->send_on_key || c->got_key_frame)
2120
                                goto send_it;
2121
                        }
2122
                    }
2123
                } else {
2124
                    AVCodecContext *codec;
2125

    
2126
                send_it:
2127
                    /* specific handling for RTP: we use several
2128
                       output stream (one for each RTP
2129
                       connection). XXX: need more abstract handling */
2130
                    if (c->is_packetized) {
2131
                        AVStream *st;
2132
                        /* compute send time and duration */
2133
                        st = c->fmt_in->streams[pkt.stream_index];
2134
                        c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2135
                        if (st->start_time != AV_NOPTS_VALUE)
2136
                            c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2137
                        c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2138
#if 0
2139
                        printf("index=%d pts=%0.3f duration=%0.6f\n",
2140
                               pkt.stream_index,
2141
                               (double)c->cur_pts /
2142
                               AV_TIME_BASE,
2143
                               (double)c->cur_frame_duration /
2144
                               AV_TIME_BASE);
2145
#endif
2146
                        /* find RTP context */
2147
                        c->packet_stream_index = pkt.stream_index;
2148
                        ctx = c->rtp_ctx[c->packet_stream_index];
2149
                        if(!ctx) {
2150
                            av_free_packet(&pkt);
2151
                            break;
2152
                        }
2153
                        codec = ctx->streams[0]->codec;
2154
                        /* only one stream per RTP connection */
2155
                        pkt.stream_index = 0;
2156
                    } else {
2157
                        ctx = &c->fmt_ctx;
2158
                        /* Fudge here */
2159
                        codec = ctx->streams[pkt.stream_index]->codec;
2160
                    }
2161

    
2162
                    if (c->is_packetized) {
2163
                        int max_packet_size;
2164
                        if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2165
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2166
                        else
2167
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2168
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2169
                    } else {
2170
                        ret = url_open_dyn_buf(&ctx->pb);
2171
                    }
2172
                    if (ret < 0) {
2173
                        /* XXX: potential leak */
2174
                        return -1;
2175
                    }
2176
                    c->fmt_ctx.pb->is_streamed = 1;
2177
                    if (pkt.dts != AV_NOPTS_VALUE)
2178
                        pkt.dts = av_rescale_q(pkt.dts,
2179
                                               c->fmt_in->streams[source_index]->time_base,
2180
                                               ctx->streams[pkt.stream_index]->time_base);
2181
                    if (pkt.pts != AV_NOPTS_VALUE)
2182
                        pkt.pts = av_rescale_q(pkt.pts,
2183
                                               c->fmt_in->streams[source_index]->time_base,
2184
                                               ctx->streams[pkt.stream_index]->time_base);
2185
                    pkt.duration = av_rescale_q(pkt.duration,
2186
                                                c->fmt_in->streams[source_index]->time_base,
2187
                                                ctx->streams[pkt.stream_index]->time_base);
2188
                    if (av_write_frame(ctx, &pkt) < 0) {
2189
                        http_log("Error writing frame to output\n");
2190
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2191
                        return 1;
2192
                    }
2193

    
2194
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2195
                    c->cur_frame_bytes = len;
2196
                    c->buffer_ptr = c->pb_buffer;
2197
                    c->buffer_end = c->pb_buffer + len;
2198

    
2199
                    codec->frame_number++;
2200
                    if (len == 0) {
2201
                        av_free_packet(&pkt);
2202
                        goto redo;
2203
                    }
2204
                }
2205
                av_free_packet(&pkt);
2206
            }
2207
        }
2208
        break;
2209
    default:
2210
    case HTTPSTATE_SEND_DATA_TRAILER:
2211
        /* last packet test ? */
2212
        if (c->last_packet_sent || c->is_packetized)
2213
            return -1;
2214
        ctx = &c->fmt_ctx;
2215
        /* prepare header */
2216
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2217
            /* XXX: potential leak */
2218
            return -1;
2219
        }
2220
        c->fmt_ctx.pb->is_streamed = 1;
2221
        av_write_trailer(ctx);
2222
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2223
        c->buffer_ptr = c->pb_buffer;
2224
        c->buffer_end = c->pb_buffer + len;
2225

    
2226
        c->last_packet_sent = 1;
2227
        break;
2228
    }
2229
    return 0;
2230
}
2231

    
2232
/* should convert the format at the same time */
2233
/* send data starting at c->buffer_ptr to the output connection
2234
   (either UDP or TCP connection) */
2235
static int http_send_data(HTTPContext *c)
2236
{
2237
    int len, ret;
2238

    
2239
    for(;;) {
2240
        if (c->buffer_ptr >= c->buffer_end) {
2241
            ret = http_prepare_data(c);
2242
            if (ret < 0)
2243
                return -1;
2244
            else if (ret != 0)
2245
                /* state change requested */
2246
                break;
2247
        } else {
2248
            if (c->is_packetized) {
2249
                /* RTP data output */
2250
                len = c->buffer_end - c->buffer_ptr;
2251
                if (len < 4) {
2252
                    /* fail safe - should never happen */
2253
                fail1:
2254
                    c->buffer_ptr = c->buffer_end;
2255
                    return 0;
2256
                }
2257
                len = (c->buffer_ptr[0] << 24) |
2258
                    (c->buffer_ptr[1] << 16) |
2259
                    (c->buffer_ptr[2] << 8) |
2260
                    (c->buffer_ptr[3]);
2261
                if (len > (c->buffer_end - c->buffer_ptr))
2262
                    goto fail1;
2263
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2264
                    /* nothing to send yet: we can wait */
2265
                    return 0;
2266
                }
2267

    
2268
                c->data_count += len;
2269
                update_datarate(&c->datarate, c->data_count);
2270
                if (c->stream)
2271
                    c->stream->bytes_served += len;
2272

    
2273
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2274
                    /* RTP packets are sent inside the RTSP TCP connection */
2275
                    ByteIOContext *pb;
2276
                    int interleaved_index, size;
2277
                    uint8_t header[4];
2278
                    HTTPContext *rtsp_c;
2279

    
2280
                    rtsp_c = c->rtsp_c;
2281
                    /* if no RTSP connection left, error */
2282
                    if (!rtsp_c)
2283
                        return -1;
2284
                    /* if already sending something, then wait. */
2285
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2286
                        break;
2287
                    if (url_open_dyn_buf(&pb) < 0)
2288
                        goto fail1;
2289
                    interleaved_index = c->packet_stream_index * 2;
2290
                    /* RTCP packets are sent at odd indexes */
2291
                    if (c->buffer_ptr[1] == 200)
2292
                        interleaved_index++;
2293
                    /* write RTSP TCP header */
2294
                    header[0] = '$';
2295
                    header[1] = interleaved_index;
2296
                    header[2] = len >> 8;
2297
                    header[3] = len;
2298
                    put_buffer(pb, header, 4);
2299
                    /* write RTP packet data */
2300
                    c->buffer_ptr += 4;
2301
                    put_buffer(pb, c->buffer_ptr, len);
2302
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2303
                    /* prepare asynchronous TCP sending */
2304
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2305
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2306
                    c->buffer_ptr += len;
2307

    
2308
                    /* send everything we can NOW */
2309
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2310
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2311
                    if (len > 0)
2312
                        rtsp_c->packet_buffer_ptr += len;
2313
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2314
                        /* if we could not send all the data, we will
2315
                           send it later, so a new state is needed to
2316
                           "lock" the RTSP TCP connection */
2317
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2318
                        break;
2319
                    } else
2320
                        /* all data has been sent */
2321
                        av_freep(&c->packet_buffer);
2322
                } else {
2323
                    /* send RTP packet directly in UDP */
2324
                    c->buffer_ptr += 4;
2325
                    url_write(c->rtp_handles[c->packet_stream_index],
2326
                              c->buffer_ptr, len);
2327
                    c->buffer_ptr += len;
2328
                    /* here we continue as we can send several packets per 10 ms slot */
2329
                }
2330
            } else {
2331
                /* TCP data output */
2332
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2333
                if (len < 0) {
2334
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2335
                        ff_neterrno() != FF_NETERROR(EINTR))
2336
                        /* error : close connection */
2337
                        return -1;
2338
                    else
2339
                        return 0;
2340
                } else
2341
                    c->buffer_ptr += len;
2342

    
2343
                c->data_count += len;
2344
                update_datarate(&c->datarate, c->data_count);
2345
                if (c->stream)
2346
                    c->stream->bytes_served += len;
2347
                break;
2348
            }
2349
        }
2350
    } /* for(;;) */
2351
    return 0;
2352
}
2353

    
2354
static int http_start_receive_data(HTTPContext *c)
2355
{
2356
    int fd;
2357

    
2358
    if (c->stream->feed_opened)
2359
        return -1;
2360

    
2361
    /* Don't permit writing to this one */
2362
    if (c->stream->readonly)
2363
        return -1;
2364

    
2365
    /* open feed */
2366
    fd = open(c->stream->feed_filename, O_RDWR);
2367
    if (fd < 0) {
2368
        http_log("Error opening feeder file: %s\n", strerror(errno));
2369
        return -1;
2370
    }
2371
    c->feed_fd = fd;
2372

    
2373
    c->stream->feed_write_index = ffm_read_write_index(fd);
2374
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2375
    lseek(fd, 0, SEEK_SET);
2376

    
2377
    /* init buffer input */
2378
    c->buffer_ptr = c->buffer;
2379
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2380
    c->stream->feed_opened = 1;
2381
    return 0;
2382
}
2383

    
2384
static int http_receive_data(HTTPContext *c)
2385
{
2386
    HTTPContext *c1;
2387

    
2388
    if (c->buffer_end > c->buffer_ptr) {
2389
        int len;
2390

    
2391
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2392
        if (len < 0) {
2393
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2394
                ff_neterrno() != FF_NETERROR(EINTR))
2395
                /* error : close connection */
2396
                goto fail;
2397
        } else if (len == 0)
2398
            /* end of connection : close it */
2399
            goto fail;
2400
        else {
2401
            c->buffer_ptr += len;
2402
            c->data_count += len;
2403
            update_datarate(&c->datarate, c->data_count);
2404
        }
2405
    }
2406

    
2407
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2408
        if (c->buffer[0] != 'f' ||
2409
            c->buffer[1] != 'm') {
2410
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2411
            goto fail;
2412
        }
2413
    }
2414

    
2415
    if (c->buffer_ptr >= c->buffer_end) {
2416
        FFStream *feed = c->stream;
2417
        /* a packet has been received : write it in the store, except
2418
           if header */
2419
        if (c->data_count > FFM_PACKET_SIZE) {
2420

    
2421
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2422
            /* XXX: use llseek or url_seek */
2423
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2424
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2425
                http_log("Error writing to feed file: %s\n", strerror(errno));
2426
                goto fail;
2427
            }
2428

    
2429
            feed->feed_write_index += FFM_PACKET_SIZE;
2430
            /* update file size */
2431
            if (feed->feed_write_index > c->stream->feed_size)
2432
                feed->feed_size = feed->feed_write_index;
2433

    
2434
            /* handle wrap around if max file size reached */
2435
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2436
                feed->feed_write_index = FFM_PACKET_SIZE;
2437

    
2438
            /* write index */
2439
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2440

    
2441
            /* wake up any waiting connections */
2442
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2443
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2444
                    c1->stream->feed == c->stream->feed)
2445
                    c1->state = HTTPSTATE_SEND_DATA;
2446
            }
2447
        } else {
2448
            /* We have a header in our hands that contains useful data */
2449
            AVFormatContext s;
2450
            AVInputFormat *fmt_in;
2451
            int i;
2452

    
2453
            memset(&s, 0, sizeof(s));
2454

    
2455
            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2456
            s.pb->is_streamed = 1;
2457

    
2458
            /* use feed output format name to find corresponding input format */
2459
            fmt_in = av_find_input_format(feed->fmt->name);
2460
            if (!fmt_in)
2461
                goto fail;
2462

    
2463
            if (fmt_in->priv_data_size > 0) {
2464
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2465
                if (!s.priv_data)
2466
                    goto fail;
2467
            } else
2468
                s.priv_data = NULL;
2469

    
2470
            if (fmt_in->read_header(&s, 0) < 0) {
2471
                av_freep(&s.priv_data);
2472
                goto fail;
2473
            }
2474

    
2475
            /* Now we have the actual streams */
2476
            if (s.nb_streams != feed->nb_streams) {
2477
                av_freep(&s.priv_data);
2478
                goto fail;
2479
            }
2480
            for (i = 0; i < s.nb_streams; i++)
2481
                memcpy(feed->streams[i]->codec,
2482
                       s.streams[i]->codec, sizeof(AVCodecContext));
2483
            av_freep(&s.priv_data);
2484
        }
2485
        c->buffer_ptr = c->buffer;
2486
    }
2487

    
2488
    return 0;
2489
 fail:
2490
    c->stream->feed_opened = 0;
2491
    close(c->feed_fd);
2492
    /* wake up any waiting connections to stop waiting for feed */
2493
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2494
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2495
            c1->stream->feed == c->stream->feed)
2496
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2497
    }
2498
    return -1;
2499
}
2500

    
2501
/********************************************************************/
2502
/* RTSP handling */
2503

    
2504
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2505
{
2506
    const char *str;
2507
    time_t ti;
2508
    char *p;
2509
    char buf2[32];
2510

    
2511
    switch(error_number) {
2512
    case RTSP_STATUS_OK:
2513
        str = "OK";
2514
        break;
2515
    case RTSP_STATUS_METHOD:
2516
        str = "Method Not Allowed";
2517
        break;
2518
    case RTSP_STATUS_BANDWIDTH:
2519
        str = "Not Enough Bandwidth";
2520
        break;
2521
    case RTSP_STATUS_SESSION:
2522
        str = "Session Not Found";
2523
        break;
2524
    case RTSP_STATUS_STATE:
2525
        str = "Method Not Valid in This State";
2526
        break;
2527
    case RTSP_STATUS_AGGREGATE:
2528
        str = "Aggregate operation not allowed";
2529
        break;
2530
    case RTSP_STATUS_ONLY_AGGREGATE:
2531
        str = "Only aggregate operation allowed";
2532
        break;
2533
    case RTSP_STATUS_TRANSPORT:
2534
        str = "Unsupported transport";
2535
        break;
2536
    case RTSP_STATUS_INTERNAL:
2537
        str = "Internal Server Error";
2538
        break;
2539
    case RTSP_STATUS_SERVICE:
2540
        str = "Service Unavailable";
2541
        break;
2542
    case RTSP_STATUS_VERSION:
2543
        str = "RTSP Version not supported";
2544
        break;
2545
    default:
2546
        str = "Unknown Error";
2547
        break;
2548
    }
2549

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

    
2553
    /* output GMT time */
2554
    ti = time(NULL);
2555
    p = ctime(&ti);
2556
    strcpy(buf2, p);
2557
    p = buf2 + strlen(p) - 1;
2558
    if (*p == '\n')
2559
        *p = '\0';
2560
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2561
}
2562

    
2563
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2564
{
2565
    rtsp_reply_header(c, error_number);
2566
    url_fprintf(c->pb, "\r\n");
2567
}
2568

    
2569
static int rtsp_parse_request(HTTPContext *c)
2570
{
2571
    const char *p, *p1, *p2;
2572
    char cmd[32];
2573
    char url[1024];
2574
    char protocol[32];
2575
    char line[1024];
2576
    int len;
2577
    RTSPHeader header1, *header = &header1;
2578

    
2579
    c->buffer_ptr[0] = '\0';
2580
    p = c->buffer;
2581

    
2582
    get_word(cmd, sizeof(cmd), &p);
2583
    get_word(url, sizeof(url), &p);
2584
    get_word(protocol, sizeof(protocol), &p);
2585

    
2586
    av_strlcpy(c->method, cmd, sizeof(c->method));
2587
    av_strlcpy(c->url, url, sizeof(c->url));
2588
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2589

    
2590
    if (url_open_dyn_buf(&c->pb) < 0) {
2591
        /* XXX: cannot do more */
2592
        c->pb = NULL; /* safety */
2593
        return -1;
2594
    }
2595

    
2596
    /* check version name */
2597
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2598
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2599
        goto the_end;
2600
    }
2601

    
2602
    /* parse each header line */
2603
    memset(header, 0, sizeof(RTSPHeader));
2604
    /* skip to next line */
2605
    while (*p != '\n' && *p != '\0')
2606
        p++;
2607
    if (*p == '\n')
2608
        p++;
2609
    while (*p != '\0') {
2610
        p1 = strchr(p, '\n');
2611
        if (!p1)
2612
            break;
2613
        p2 = p1;
2614
        if (p2 > p && p2[-1] == '\r')
2615
            p2--;
2616
        /* skip empty line */
2617
        if (p2 == p)
2618
            break;
2619
        len = p2 - p;
2620
        if (len > sizeof(line) - 1)
2621
            len = sizeof(line) - 1;
2622
        memcpy(line, p, len);
2623
        line[len] = '\0';
2624
        rtsp_parse_line(header, line);
2625
        p = p1 + 1;
2626
    }
2627

    
2628
    /* handle sequence number */
2629
    c->seq = header->seq;
2630

    
2631
    if (!strcmp(cmd, "DESCRIBE"))
2632
        rtsp_cmd_describe(c, url);
2633
    else if (!strcmp(cmd, "OPTIONS"))
2634
        rtsp_cmd_options(c, url);
2635
    else if (!strcmp(cmd, "SETUP"))
2636
        rtsp_cmd_setup(c, url, header);
2637
    else if (!strcmp(cmd, "PLAY"))
2638
        rtsp_cmd_play(c, url, header);
2639
    else if (!strcmp(cmd, "PAUSE"))
2640
        rtsp_cmd_pause(c, url, header);
2641
    else if (!strcmp(cmd, "TEARDOWN"))
2642
        rtsp_cmd_teardown(c, url, header);
2643
    else
2644
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2645

    
2646
 the_end:
2647
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2648
    c->pb = NULL; /* safety */
2649
    if (len < 0) {
2650
        /* XXX: cannot do more */
2651
        return -1;
2652
    }
2653
    c->buffer_ptr = c->pb_buffer;
2654
    c->buffer_end = c->pb_buffer + len;
2655
    c->state = RTSPSTATE_SEND_REPLY;
2656
    return 0;
2657
}
2658

    
2659
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2660
                                   struct in_addr my_ip)
2661
{
2662
    AVFormatContext *avc;
2663
    AVStream avs[MAX_STREAMS];
2664
    int i;
2665

    
2666
    avc =  av_alloc_format_context();
2667
    if (avc == NULL) {
2668
        return -1;
2669
    }
2670
    if (stream->title[0] != 0) {
2671
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2672
    } else {
2673
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2674
    }
2675
    avc->nb_streams = stream->nb_streams;
2676
    if (stream->is_multicast) {
2677
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2678
                 inet_ntoa(stream->multicast_ip),
2679
                 stream->multicast_port, stream->multicast_ttl);
2680
    }
2681

    
2682
    for(i = 0; i < stream->nb_streams; i++) {
2683
        avc->streams[i] = &avs[i];
2684
        avc->streams[i]->codec = stream->streams[i]->codec;
2685
    }
2686
    *pbuffer = av_mallocz(2048);
2687
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2688
    av_free(avc);
2689

    
2690
    return strlen(*pbuffer);
2691
}
2692

    
2693
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2694
{
2695
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2696
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2697
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2698
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2699
    url_fprintf(c->pb, "\r\n");
2700
}
2701

    
2702
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2703
{
2704
    FFStream *stream;
2705
    char path1[1024];
2706
    const char *path;
2707
    uint8_t *content;
2708
    int content_length, len;
2709
    struct sockaddr_in my_addr;
2710

    
2711
    /* find which url is asked */
2712
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2713
    path = path1;
2714
    if (*path == '/')
2715
        path++;
2716

    
2717
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2718
        if (!stream->is_feed &&
2719
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2720
            !strcmp(path, stream->filename)) {
2721
            goto found;
2722
        }
2723
    }
2724
    /* no stream found */
2725
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2726
    return;
2727

    
2728
 found:
2729
    /* prepare the media description in sdp format */
2730

    
2731
    /* get the host IP */
2732
    len = sizeof(my_addr);
2733
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2734
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2735
    if (content_length < 0) {
2736
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2737
        return;
2738
    }
2739
    rtsp_reply_header(c, RTSP_STATUS_OK);
2740
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2741
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2742
    url_fprintf(c->pb, "\r\n");
2743
    put_buffer(c->pb, content, content_length);
2744
}
2745

    
2746
static HTTPContext *find_rtp_session(const char *session_id)
2747
{
2748
    HTTPContext *c;
2749

    
2750
    if (session_id[0] == '\0')
2751
        return NULL;
2752

    
2753
    for(c = first_http_ctx; c != NULL; c = c->next) {
2754
        if (!strcmp(c->session_id, session_id))
2755
            return c;
2756
    }
2757
    return NULL;
2758
}
2759

    
2760
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2761
{
2762
    RTSPTransportField *th;
2763
    int i;
2764

    
2765
    for(i=0;i<h->nb_transports;i++) {
2766
        th = &h->transports[i];
2767
        if (th->protocol == protocol)
2768
            return th;
2769
    }
2770
    return NULL;
2771
}
2772

    
2773
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2774
                           RTSPHeader *h)
2775
{
2776
    FFStream *stream;
2777
    int stream_index, port;
2778
    char buf[1024];
2779
    char path1[1024];
2780
    const char *path;
2781
    HTTPContext *rtp_c;
2782
    RTSPTransportField *th;
2783
    struct sockaddr_in dest_addr;
2784
    RTSPActionServerSetup setup;
2785

    
2786
    /* find which url is asked */
2787
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2788
    path = path1;
2789
    if (*path == '/')
2790
        path++;
2791

    
2792
    /* now check each stream */
2793
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2794
        if (!stream->is_feed &&
2795
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2796
            /* accept aggregate filenames only if single stream */
2797
            if (!strcmp(path, stream->filename)) {
2798
                if (stream->nb_streams != 1) {
2799
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2800
                    return;
2801
                }
2802
                stream_index = 0;
2803
                goto found;
2804
            }
2805

    
2806
            for(stream_index = 0; stream_index < stream->nb_streams;
2807
                stream_index++) {
2808
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2809
                         stream->filename, stream_index);
2810
                if (!strcmp(path, buf))
2811
                    goto found;
2812
            }
2813
        }
2814
    }
2815
    /* no stream found */
2816
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2817
    return;
2818
 found:
2819

    
2820
    /* generate session id if needed */
2821
    if (h->session_id[0] == '\0')
2822
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2823
                 av_random(&random_state), av_random(&random_state));
2824

    
2825
    /* find rtp session, and create it if none found */
2826
    rtp_c = find_rtp_session(h->session_id);
2827
    if (!rtp_c) {
2828
        /* always prefer UDP */
2829
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2830
        if (!th) {
2831
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2832
            if (!th) {
2833
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2834
                return;
2835
            }
2836
        }
2837

    
2838
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2839
                                   th->protocol);
2840
        if (!rtp_c) {
2841
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2842
            return;
2843
        }
2844

    
2845
        /* open input stream */
2846
        if (open_input_stream(rtp_c, "") < 0) {
2847
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2848
            return;
2849
        }
2850
    }
2851

    
2852
    /* test if stream is OK (test needed because several SETUP needs
2853
       to be done for a given file) */
2854
    if (rtp_c->stream != stream) {
2855
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2856
        return;
2857
    }
2858

    
2859
    /* test if stream is already set up */
2860
    if (rtp_c->rtp_ctx[stream_index]) {
2861
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2862
        return;
2863
    }
2864

    
2865
    /* check transport */
2866
    th = find_transport(h, rtp_c->rtp_protocol);
2867
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2868
                th->client_port_min <= 0)) {
2869
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2870
        return;
2871
    }
2872

    
2873
    /* setup default options */
2874
    setup.transport_option[0] = '\0';
2875
    dest_addr = rtp_c->from_addr;
2876
    dest_addr.sin_port = htons(th->client_port_min);
2877

    
2878
    /* setup stream */
2879
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2880
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2881
        return;
2882
    }
2883

    
2884
    /* now everything is OK, so we can send the connection parameters */
2885
    rtsp_reply_header(c, RTSP_STATUS_OK);
2886
    /* session ID */
2887
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2888

    
2889
    switch(rtp_c->rtp_protocol) {
2890
    case RTSP_PROTOCOL_RTP_UDP:
2891
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2892
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2893
                    "client_port=%d-%d;server_port=%d-%d",
2894
                    th->client_port_min, th->client_port_min + 1,
2895
                    port, port + 1);
2896
        break;
2897
    case RTSP_PROTOCOL_RTP_TCP:
2898
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2899
                    stream_index * 2, stream_index * 2 + 1);
2900
        break;
2901
    default:
2902
        break;
2903
    }
2904
    if (setup.transport_option[0] != '\0')
2905
        url_fprintf(c->pb, ";%s", setup.transport_option);
2906
    url_fprintf(c->pb, "\r\n");
2907

    
2908

    
2909
    url_fprintf(c->pb, "\r\n");
2910
}
2911

    
2912

    
2913
/* find an rtp connection by using the session ID. Check consistency
2914
   with filename */
2915
static HTTPContext *find_rtp_session_with_url(const char *url,
2916
                                              const char *session_id)
2917
{
2918
    HTTPContext *rtp_c;
2919
    char path1[1024];
2920
    const char *path;
2921
    char buf[1024];
2922
    int s;
2923

    
2924
    rtp_c = find_rtp_session(session_id);
2925
    if (!rtp_c)
2926
        return NULL;
2927

    
2928
    /* find which url is asked */
2929
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2930
    path = path1;
2931
    if (*path == '/')
2932
        path++;
2933
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2934
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2935
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2936
        rtp_c->stream->filename, s);
2937
      if(!strncmp(path, buf, sizeof(buf))) {
2938
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2939
        return rtp_c;
2940
      }
2941
    }
2942
    return NULL;
2943
}
2944

    
2945
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2946
{
2947
    HTTPContext *rtp_c;
2948

    
2949
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2950
    if (!rtp_c) {
2951
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2952
        return;
2953
    }
2954

    
2955
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2956
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2957
        rtp_c->state != HTTPSTATE_READY) {
2958
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2959
        return;
2960
    }
2961

    
2962
#if 0
2963
    /* XXX: seek in stream */
2964
    if (h->range_start != AV_NOPTS_VALUE) {
2965
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2966
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2967
    }
2968
#endif
2969

    
2970
    rtp_c->state = HTTPSTATE_SEND_DATA;
2971

    
2972
    /* now everything is OK, so we can send the connection parameters */
2973
    rtsp_reply_header(c, RTSP_STATUS_OK);
2974
    /* session ID */
2975
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2976
    url_fprintf(c->pb, "\r\n");
2977
}
2978

    
2979
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2980
{
2981
    HTTPContext *rtp_c;
2982

    
2983
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2984
    if (!rtp_c) {
2985
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2986
        return;
2987
    }
2988

    
2989
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2990
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2991
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2992
        return;
2993
    }
2994

    
2995
    rtp_c->state = HTTPSTATE_READY;
2996
    rtp_c->first_pts = AV_NOPTS_VALUE;
2997
    /* now everything is OK, so we can send the connection parameters */
2998
    rtsp_reply_header(c, RTSP_STATUS_OK);
2999
    /* session ID */
3000
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3001
    url_fprintf(c->pb, "\r\n");
3002
}
3003

    
3004
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3005
{
3006
    HTTPContext *rtp_c;
3007
    char session_id[32];
3008

    
3009
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3010
    if (!rtp_c) {
3011
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3012
        return;
3013
    }
3014

    
3015
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3016

    
3017
    /* abort the session */
3018
    close_connection(rtp_c);
3019

    
3020
    /* now everything is OK, so we can send the connection parameters */
3021
    rtsp_reply_header(c, RTSP_STATUS_OK);
3022
    /* session ID */
3023
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3024
    url_fprintf(c->pb, "\r\n");
3025
}
3026

    
3027

    
3028
/********************************************************************/
3029
/* RTP handling */
3030

    
3031
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3032
                                       FFStream *stream, const char *session_id,
3033
                                       enum RTSPProtocol rtp_protocol)
3034
{
3035
    HTTPContext *c = NULL;
3036
    const char *proto_str;
3037

    
3038
    /* XXX: should output a warning page when coming
3039
       close to the connection limit */
3040
    if (nb_connections >= nb_max_connections)
3041
        goto fail;
3042

    
3043
    /* add a new connection */
3044
    c = av_mallocz(sizeof(HTTPContext));
3045
    if (!c)
3046
        goto fail;
3047

    
3048
    c->fd = -1;
3049
    c->poll_entry = NULL;
3050
    c->from_addr = *from_addr;
3051
    c->buffer_size = IOBUFFER_INIT_SIZE;
3052
    c->buffer = av_malloc(c->buffer_size);
3053
    if (!c->buffer)
3054
        goto fail;
3055
    nb_connections++;
3056
    c->stream = stream;
3057
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3058
    c->state = HTTPSTATE_READY;
3059
    c->is_packetized = 1;
3060
    c->rtp_protocol = rtp_protocol;
3061

    
3062
    /* protocol is shown in statistics */
3063
    switch(c->rtp_protocol) {
3064
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3065
        proto_str = "MCAST";
3066
        break;
3067
    case RTSP_PROTOCOL_RTP_UDP:
3068
        proto_str = "UDP";
3069
        break;
3070
    case RTSP_PROTOCOL_RTP_TCP:
3071
        proto_str = "TCP";
3072
        break;
3073
    default:
3074
        proto_str = "???";
3075
        break;
3076
    }
3077
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3078
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3079

    
3080
    current_bandwidth += stream->bandwidth;
3081

    
3082
    c->next = first_http_ctx;
3083
    first_http_ctx = c;
3084
    return c;
3085

    
3086
 fail:
3087
    if (c) {
3088
        av_free(c->buffer);
3089
        av_free(c);
3090
    }
3091
    return NULL;
3092
}
3093

    
3094
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3095
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3096
   used. */
3097
static int rtp_new_av_stream(HTTPContext *c,
3098
                             int stream_index, struct sockaddr_in *dest_addr,
3099
                             HTTPContext *rtsp_c)
3100
{
3101
    AVFormatContext *ctx;
3102
    AVStream *st;
3103
    char *ipaddr;
3104
    URLContext *h = NULL;
3105
    uint8_t *dummy_buf;
3106
    char buf2[32];
3107
    int max_packet_size;
3108

    
3109
    /* now we can open the relevant output stream */
3110
    ctx = av_alloc_format_context();
3111
    if (!ctx)
3112
        return -1;
3113
    ctx->oformat = guess_format("rtp", NULL, NULL);
3114

    
3115
    st = av_mallocz(sizeof(AVStream));
3116
    if (!st)
3117
        goto fail;
3118
    st->codec= avcodec_alloc_context();
3119
    ctx->nb_streams = 1;
3120
    ctx->streams[0] = st;
3121

    
3122
    if (!c->stream->feed ||
3123
        c->stream->feed == c->stream)
3124
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3125
    else
3126
        memcpy(st,
3127
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3128
               sizeof(AVStream));
3129
    st->priv_data = NULL;
3130

    
3131
    /* build destination RTP address */
3132
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3133

    
3134
    switch(c->rtp_protocol) {
3135
    case RTSP_PROTOCOL_RTP_UDP:
3136
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3137
        /* RTP/UDP case */
3138

    
3139
        /* XXX: also pass as parameter to function ? */
3140
        if (c->stream->is_multicast) {
3141
            int ttl;
3142
            ttl = c->stream->multicast_ttl;
3143
            if (!ttl)
3144
                ttl = 16;
3145
            snprintf(ctx->filename, sizeof(ctx->filename),
3146
                     "rtp://%s:%d?multicast=1&ttl=%d",
3147
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3148
        } else {
3149
            snprintf(ctx->filename, sizeof(ctx->filename),
3150
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3151
        }
3152

    
3153
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3154
            goto fail;
3155
        c->rtp_handles[stream_index] = h;
3156
        max_packet_size = url_get_max_packet_size(h);
3157
        break;
3158
    case RTSP_PROTOCOL_RTP_TCP:
3159
        /* RTP/TCP case */
3160
        c->rtsp_c = rtsp_c;
3161
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3162
        break;
3163
    default:
3164
        goto fail;
3165
    }
3166

    
3167
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3168
             ipaddr, ntohs(dest_addr->sin_port),
3169
             ctime1(buf2),
3170
             c->stream->filename, stream_index, c->protocol);
3171

    
3172
    /* normally, no packets should be output here, but the packet size may be checked */
3173
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3174
        /* XXX: close stream */
3175
        goto fail;
3176
    }
3177
    av_set_parameters(ctx, NULL);
3178
    if (av_write_header(ctx) < 0) {
3179
    fail:
3180
        if (h)
3181
            url_close(h);
3182
        av_free(ctx);
3183
        return -1;
3184
    }
3185
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3186
    av_free(dummy_buf);
3187

    
3188
    c->rtp_ctx[stream_index] = ctx;
3189
    return 0;
3190
}
3191

    
3192
/********************************************************************/
3193
/* ffserver initialization */
3194

    
3195
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3196
{
3197
    AVStream *fst;
3198

    
3199
    fst = av_mallocz(sizeof(AVStream));
3200
    if (!fst)
3201
        return NULL;
3202
    fst->codec= avcodec_alloc_context();
3203
    fst->priv_data = av_mallocz(sizeof(FeedData));
3204
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3205
    fst->index = stream->nb_streams;
3206
    av_set_pts_info(fst, 33, 1, 90000);
3207
    stream->streams[stream->nb_streams++] = fst;
3208
    return fst;
3209
}
3210

    
3211
/* return the stream number in the feed */
3212
static int add_av_stream(FFStream *feed, AVStream *st)
3213
{
3214
    AVStream *fst;
3215
    AVCodecContext *av, *av1;
3216
    int i;
3217

    
3218
    av = st->codec;
3219
    for(i=0;i<feed->nb_streams;i++) {
3220
        st = feed->streams[i];
3221
        av1 = st->codec;
3222
        if (av1->codec_id == av->codec_id &&
3223
            av1->codec_type == av->codec_type &&
3224
            av1->bit_rate == av->bit_rate) {
3225

    
3226
            switch(av->codec_type) {
3227
            case CODEC_TYPE_AUDIO:
3228
                if (av1->channels == av->channels &&
3229
                    av1->sample_rate == av->sample_rate)
3230
                    goto found;
3231
                break;
3232
            case CODEC_TYPE_VIDEO:
3233
                if (av1->width == av->width &&
3234
                    av1->height == av->height &&
3235
                    av1->time_base.den == av->time_base.den &&
3236
                    av1->time_base.num == av->time_base.num &&
3237
                    av1->gop_size == av->gop_size)
3238
                    goto found;
3239
                break;
3240
            default:
3241
                abort();
3242
            }
3243
        }
3244
    }
3245

    
3246
    fst = add_av_stream1(feed, av);
3247
    if (!fst)
3248
        return -1;
3249
    return feed->nb_streams - 1;
3250
 found:
3251
    return i;
3252
}
3253

    
3254
static void remove_stream(FFStream *stream)
3255
{
3256
    FFStream **ps;
3257
    ps = &first_stream;
3258
    while (*ps != NULL) {
3259
        if (*ps == stream)
3260
            *ps = (*ps)->next;
3261
        else
3262
            ps = &(*ps)->next;
3263
    }
3264
}
3265

    
3266
/* specific mpeg4 handling : we extract the raw parameters */
3267
static void extract_mpeg4_header(AVFormatContext *infile)
3268
{
3269
    int mpeg4_count, i, size;
3270
    AVPacket pkt;
3271
    AVStream *st;
3272
    const uint8_t *p;
3273

    
3274
    mpeg4_count = 0;
3275
    for(i=0;i<infile->nb_streams;i++) {
3276
        st = infile->streams[i];
3277
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3278
            st->codec->extradata_size == 0) {
3279
            mpeg4_count++;
3280
        }
3281
    }
3282
    if (!mpeg4_count)
3283
        return;
3284

    
3285
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3286
    while (mpeg4_count > 0) {
3287
        if (av_read_packet(infile, &pkt) < 0)
3288
            break;
3289
        st = infile->streams[pkt.stream_index];
3290
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3291
            st->codec->extradata_size == 0) {
3292
            av_freep(&st->codec->extradata);
3293
            /* fill extradata with the header */
3294
            /* XXX: we make hard suppositions here ! */
3295
            p = pkt.data;
3296
            while (p < pkt.data + pkt.size - 4) {
3297
                /* stop when vop header is found */
3298
                if (p[0] == 0x00 && p[1] == 0x00 &&
3299
                    p[2] == 0x01 && p[3] == 0xb6) {
3300
                    size = p - pkt.data;
3301
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3302
                    st->codec->extradata = av_malloc(size);
3303
                    st->codec->extradata_size = size;
3304
                    memcpy(st->codec->extradata, pkt.data, size);
3305
                    break;
3306
                }
3307
                p++;
3308
            }
3309
            mpeg4_count--;
3310
        }
3311
        av_free_packet(&pkt);
3312
    }
3313
}
3314

    
3315
/* compute the needed AVStream for each file */
3316
static void build_file_streams(void)
3317
{
3318
    FFStream *stream, *stream_next;
3319
    AVFormatContext *infile;
3320
    int i, ret;
3321

    
3322
    /* gather all streams */
3323
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3324
        stream_next = stream->next;
3325
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3326
            !stream->feed) {
3327
            /* the stream comes from a file */
3328
            /* try to open the file */
3329
            /* open stream */
3330
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3331
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3332
                /* specific case : if transport stream output to RTP,
3333
                   we use a raw transport stream reader */
3334
                stream->ap_in->mpeg2ts_raw = 1;
3335
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3336
            }
3337

    
3338
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3339
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3340
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3341
                /* remove stream (no need to spend more time on it) */
3342
            fail:
3343
                remove_stream(stream);
3344
            } else {
3345
                /* find all the AVStreams inside and reference them in
3346
                   'stream' */
3347
                if (av_find_stream_info(infile) < 0) {
3348
                    http_log("Could not find codec parameters from '%s'\n",
3349
                             stream->feed_filename);
3350
                    av_close_input_file(infile);
3351
                    goto fail;
3352
                }
3353
                extract_mpeg4_header(infile);
3354

    
3355
                for(i=0;i<infile->nb_streams;i++)
3356
                    add_av_stream1(stream, infile->streams[i]->codec);
3357

    
3358
                av_close_input_file(infile);
3359
            }
3360
        }
3361
    }
3362
}
3363

    
3364
/* compute the needed AVStream for each feed */
3365
static void build_feed_streams(void)
3366
{
3367
    FFStream *stream, *feed;
3368
    int i;
3369

    
3370
    /* gather all streams */
3371
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3372
        feed = stream->feed;
3373
        if (feed) {
3374
            if (!stream->is_feed) {
3375
                /* we handle a stream coming from a feed */
3376
                for(i=0;i<stream->nb_streams;i++)
3377
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3378
            }
3379
        }
3380
    }
3381

    
3382
    /* gather all streams */
3383
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3384
        feed = stream->feed;
3385
        if (feed) {
3386
            if (stream->is_feed) {
3387
                for(i=0;i<stream->nb_streams;i++)
3388
                    stream->feed_streams[i] = i;
3389
            }
3390
        }
3391
    }
3392

    
3393
    /* create feed files if needed */
3394
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3395
        int fd;
3396

    
3397
        if (url_exist(feed->feed_filename)) {
3398
            /* See if it matches */
3399
            AVFormatContext *s;
3400
            int matches = 0;
3401

    
3402
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3403
                /* Now see if it matches */
3404
                if (s->nb_streams == feed->nb_streams) {
3405
                    matches = 1;
3406
                    for(i=0;i<s->nb_streams;i++) {
3407
                        AVStream *sf, *ss;
3408
                        sf = feed->streams[i];
3409
                        ss = s->streams[i];
3410

    
3411
                        if (sf->index != ss->index ||
3412
                            sf->id != ss->id) {
3413
                            printf("Index & Id do not match for stream %d (%s)\n",
3414
                                   i, feed->feed_filename);
3415
                            matches = 0;
3416
                        } else {
3417
                            AVCodecContext *ccf, *ccs;
3418

    
3419
                            ccf = sf->codec;
3420
                            ccs = ss->codec;
3421
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3422

    
3423
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3424
                                printf("Codecs do not match for stream %d\n", i);
3425
                                matches = 0;
3426
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3427
                                printf("Codec bitrates do not match for stream %d\n", i);
3428
                                matches = 0;
3429
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3430
                                if (CHECK_CODEC(time_base.den) ||
3431
                                    CHECK_CODEC(time_base.num) ||
3432
                                    CHECK_CODEC(width) ||
3433
                                    CHECK_CODEC(height)) {
3434
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3435
                                    matches = 0;
3436
                                }
3437
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3438
                                if (CHECK_CODEC(sample_rate) ||
3439
                                    CHECK_CODEC(channels) ||
3440
                                    CHECK_CODEC(frame_size)) {
3441
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3442
                                    matches = 0;
3443
                                }
3444
                            } else {
3445
                                printf("Unknown codec type\n");
3446
                                matches = 0;
3447
                            }
3448
                        }
3449
                        if (!matches)
3450
                            break;
3451
                    }
3452
                } else
3453
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3454
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3455

    
3456
                av_close_input_file(s);
3457
            } else
3458
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3459
                        feed->feed_filename);
3460

    
3461
            if (!matches) {
3462
                if (feed->readonly) {
3463
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3464
                        feed->feed_filename);
3465
                    exit(1);
3466
                }
3467
                unlink(feed->feed_filename);
3468
            }
3469
        }
3470
        if (!url_exist(feed->feed_filename)) {
3471
            AVFormatContext s1, *s = &s1;
3472

    
3473
            if (feed->readonly) {
3474
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3475
                    feed->feed_filename);
3476
                exit(1);
3477
            }
3478

    
3479
            /* only write the header of the ffm file */
3480
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3481
                http_log("Could not open output feed file '%s'\n",
3482
                         feed->feed_filename);
3483
                exit(1);
3484
            }
3485
            s->oformat = feed->fmt;
3486
            s->nb_streams = feed->nb_streams;
3487
            for(i=0;i<s->nb_streams;i++) {
3488
                AVStream *st;
3489
                st = feed->streams[i];
3490
                s->streams[i] = st;
3491
            }
3492
            av_set_parameters(s, NULL);
3493
            if (av_write_header(s) < 0) {
3494
                http_log("Container doesn't supports the required parameters\n");
3495
                exit(1);
3496
            }
3497
            /* XXX: need better api */
3498
            av_freep(&s->priv_data);
3499
            url_fclose(s->pb);
3500
        }
3501
        /* get feed size and write index */
3502
        fd = open(feed->feed_filename, O_RDONLY);
3503
        if (fd < 0) {
3504
            http_log("Could not open output feed file '%s'\n",
3505
                    feed->feed_filename);
3506
            exit(1);
3507
        }
3508

    
3509
        feed->feed_write_index = ffm_read_write_index(fd);
3510
        feed->feed_size = lseek(fd, 0, SEEK_END);
3511
        /* ensure that we do not wrap before the end of file */
3512
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3513
            feed->feed_max_size = feed->feed_size;
3514

    
3515
        close(fd);
3516
    }
3517
}
3518

    
3519
/* compute the bandwidth used by each stream */
3520
static void compute_bandwidth(void)
3521
{
3522
    unsigned bandwidth;
3523
    int i;
3524
    FFStream *stream;
3525

    
3526
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3527
        bandwidth = 0;
3528
        for(i=0;i<stream->nb_streams;i++) {
3529
            AVStream *st = stream->streams[i];
3530
            switch(st->codec->codec_type) {
3531
            case CODEC_TYPE_AUDIO:
3532
            case CODEC_TYPE_VIDEO:
3533
                bandwidth += st->codec->bit_rate;
3534
                break;
3535
            default:
3536
                break;
3537
            }
3538
        }
3539
        stream->bandwidth = (bandwidth + 999) / 1000;
3540
    }
3541
}
3542

    
3543
static void get_arg(char *buf, int buf_size, const char **pp)
3544
{
3545
    const char *p;
3546
    char *q;
3547
    int quote;
3548

    
3549
    p = *pp;
3550
    while (isspace(*p)) p++;
3551
    q = buf;
3552
    quote = 0;
3553
    if (*p == '\"' || *p == '\'')
3554
        quote = *p++;
3555
    for(;;) {
3556
        if (quote) {
3557
            if (*p == quote)
3558
                break;
3559
        } else {
3560
            if (isspace(*p))
3561
                break;
3562
        }
3563
        if (*p == '\0')
3564
            break;
3565
        if ((q - buf) < buf_size - 1)
3566
            *q++ = *p;
3567
        p++;
3568
    }
3569
    *q = '\0';
3570
    if (quote && *p == quote)
3571
        p++;
3572
    *pp = p;
3573
}
3574

    
3575
/* add a codec and set the default parameters */
3576
static void add_codec(FFStream *stream, AVCodecContext *av)
3577
{
3578
    AVStream *st;
3579

    
3580
    /* compute default parameters */
3581
    switch(av->codec_type) {
3582
    case CODEC_TYPE_AUDIO:
3583
        if (av->bit_rate == 0)
3584
            av->bit_rate = 64000;
3585
        if (av->sample_rate == 0)
3586
            av->sample_rate = 22050;
3587
        if (av->channels == 0)
3588
            av->channels = 1;
3589
        break;
3590
    case CODEC_TYPE_VIDEO:
3591
        if (av->bit_rate == 0)
3592
            av->bit_rate = 64000;
3593
        if (av->time_base.num == 0){
3594
            av->time_base.den = 5;
3595
            av->time_base.num = 1;
3596
        }
3597
        if (av->width == 0 || av->height == 0) {
3598
            av->width = 160;
3599
            av->height = 128;
3600
        }
3601
        /* Bitrate tolerance is less for streaming */
3602
        if (av->bit_rate_tolerance == 0)
3603
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3604
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3605
        if (av->qmin == 0)
3606
            av->qmin = 3;
3607
        if (av->qmax == 0)
3608
            av->qmax = 31;
3609
        if (av->max_qdiff == 0)
3610
            av->max_qdiff = 3;
3611
        av->qcompress = 0.5;
3612
        av->qblur = 0.5;
3613

    
3614
        if (!av->nsse_weight)
3615
            av->nsse_weight = 8;
3616

    
3617
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3618
        av->me_method = ME_EPZS;
3619
        av->rc_buffer_aggressivity = 1.0;
3620

    
3621
        if (!av->rc_eq)
3622
            av->rc_eq = "tex^qComp";
3623
        if (!av->i_quant_factor)
3624
            av->i_quant_factor = -0.8;
3625
        if (!av->b_quant_factor)
3626
            av->b_quant_factor = 1.25;
3627
        if (!av->b_quant_offset)
3628
            av->b_quant_offset = 1.25;
3629
        if (!av->rc_max_rate)
3630
            av->rc_max_rate = av->bit_rate * 2;
3631

    
3632
        if (av->rc_max_rate && !av->rc_buffer_size) {
3633
            av->rc_buffer_size = av->rc_max_rate;
3634
        }
3635

    
3636

    
3637
        break;
3638
    default:
3639
        abort();
3640
    }
3641

    
3642
    st = av_mallocz(sizeof(AVStream));
3643
    if (!st)
3644
        return;
3645
    st->codec = avcodec_alloc_context();
3646
    stream->streams[stream->nb_streams++] = st;
3647
    memcpy(st->codec, av, sizeof(AVCodecContext));
3648
}
3649

    
3650
static int opt_audio_codec(const char *arg)
3651
{
3652
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3653

    
3654
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3655
        return CODEC_ID_NONE;
3656

    
3657
    return p->id;
3658
}
3659

    
3660
static int opt_video_codec(const char *arg)
3661
{
3662
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3663

    
3664
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3665
        return CODEC_ID_NONE;
3666

    
3667
    return p->id;
3668
}
3669

    
3670
/* simplistic plugin support */
3671

    
3672
#ifdef HAVE_DLOPEN
3673
static void load_module(const char *filename)
3674
{
3675
    void *dll;
3676
    void (*init_func)(void);
3677
    dll = dlopen(filename, RTLD_NOW);
3678
    if (!dll) {
3679
        fprintf(stderr, "Could not load module '%s' - %s\n",
3680
                filename, dlerror());
3681
        return;
3682
    }
3683

    
3684
    init_func = dlsym(dll, "ffserver_module_init");
3685
    if (!init_func) {
3686
        fprintf(stderr,
3687
                "%s: init function 'ffserver_module_init()' not found\n",
3688
                filename);
3689
        dlclose(dll);
3690
    }
3691

    
3692
    init_func();
3693
}
3694
#endif
3695

    
3696
static int opt_default(const char *opt, const char *arg,
3697
                       AVCodecContext *avctx, int type)
3698
{
3699
    const AVOption *o  = NULL;
3700
    const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3701
    if(o2)
3702
        o = av_set_string(avctx, opt, arg);
3703
    if(!o)
3704
        return -1;
3705
    return 0;
3706
}
3707

    
3708
static int parse_ffconfig(const char *filename)
3709
{
3710
    FILE *f;
3711
    char line[1024];
3712
    char cmd[64];
3713
    char arg[1024];
3714
    const char *p;
3715
    int val, errors, line_num;
3716
    FFStream **last_stream, *stream, *redirect;
3717
    FFStream **last_feed, *feed;
3718
    AVCodecContext audio_enc, video_enc;
3719
    int audio_id, video_id;
3720

    
3721
    f = fopen(filename, "r");
3722
    if (!f) {
3723
        perror(filename);
3724
        return -1;
3725
    }
3726

    
3727
    errors = 0;
3728
    line_num = 0;
3729
    first_stream = NULL;
3730
    last_stream = &first_stream;
3731
    first_feed = NULL;
3732
    last_feed = &first_feed;
3733
    stream = NULL;
3734
    feed = NULL;
3735
    redirect = NULL;
3736
    audio_id = CODEC_ID_NONE;
3737
    video_id = CODEC_ID_NONE;
3738
    for(;;) {
3739
        if (fgets(line, sizeof(line), f) == NULL)
3740
            break;
3741
        line_num++;
3742
        p = line;
3743
        while (isspace(*p))
3744
            p++;
3745
        if (*p == '\0' || *p == '#')
3746
            continue;
3747

    
3748
        get_arg(cmd, sizeof(cmd), &p);
3749

    
3750
        if (!strcasecmp(cmd, "Port")) {
3751
            get_arg(arg, sizeof(arg), &p);
3752
            val = atoi(arg);
3753
            if (val < 1 || val > 65536) {
3754
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3755
                        filename, line_num, arg);
3756
                errors++;
3757
            }
3758
            my_http_addr.sin_port = htons(val);
3759
        } else if (!strcasecmp(cmd, "BindAddress")) {
3760
            get_arg(arg, sizeof(arg), &p);
3761
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3762
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3763
                        filename, line_num, arg);
3764
                errors++;
3765
            }
3766
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3767
            ffserver_daemon = 0;
3768
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3769
            get_arg(arg, sizeof(arg), &p);
3770
            val = atoi(arg);
3771
            if (val < 1 || val > 65536) {
3772
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3773
                        filename, line_num, arg);
3774
                errors++;
3775
            }
3776
            my_rtsp_addr.sin_port = htons(atoi(arg));
3777
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3778
            get_arg(arg, sizeof(arg), &p);
3779
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3780
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3781
                        filename, line_num, arg);
3782
                errors++;
3783
            }
3784
        } else if (!strcasecmp(cmd, "MaxClients")) {
3785
            get_arg(arg, sizeof(arg), &p);
3786
            val = atoi(arg);
3787
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3788
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3789
                        filename, line_num, arg);
3790
                errors++;
3791
            } else {
3792
                nb_max_connections = val;
3793
            }
3794
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3795
            int64_t llval;
3796
            get_arg(arg, sizeof(arg), &p);
3797
            llval = atoll(arg);
3798
            if (llval < 10 || llval > 10000000) {
3799
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3800
                        filename, line_num, arg);
3801
                errors++;
3802
            } else
3803
                max_bandwidth = llval;
3804
        } else if (!strcasecmp(cmd, "CustomLog")) {
3805
            if (!ffserver_debug)
3806
                get_arg(logfilename, sizeof(logfilename), &p);
3807
        } else if (!strcasecmp(cmd, "<Feed")) {
3808
            /*********************************************/
3809
            /* Feed related options */
3810
            char *q;
3811
            if (stream || feed) {
3812
                fprintf(stderr, "%s:%d: Already in a tag\n",
3813
                        filename, line_num);
3814
            } else {
3815
                feed = av_mallocz(sizeof(FFStream));
3816
                /* add in stream list */
3817
                *last_stream = feed;
3818
                last_stream = &feed->next;
3819
                /* add in feed list */
3820
                *last_feed = feed;
3821
                last_feed = &feed->next_feed;
3822

    
3823
                get_arg(feed->filename, sizeof(feed->filename), &p);
3824
                q = strrchr(feed->filename, '>');
3825
                if (*q)
3826
                    *q = '\0';
3827
                feed->fmt = guess_format("ffm", NULL, NULL);
3828
                /* defaut feed file */
3829
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3830
                         "/tmp/%s.ffm", feed->filename);
3831
                feed->feed_max_size = 5 * 1024 * 1024;
3832
                feed->is_feed = 1;
3833
                feed->feed = feed; /* self feeding :-) */
3834
            }
3835
        } else if (!strcasecmp(cmd, "Launch")) {
3836
            if (feed) {
3837
                int i;
3838

    
3839
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3840

    
3841
                for (i = 0; i < 62; i++) {
3842
                    get_arg(arg, sizeof(arg), &p);
3843
                    if (!arg[0])
3844
                        break;
3845

    
3846
                    feed->child_argv[i] = av_strdup(arg);
3847
                }
3848

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

    
3851
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3852
                    "http://%s:%d/%s",
3853
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3854
                    inet_ntoa(my_http_addr.sin_addr),
3855
                    ntohs(my_http_addr.sin_port), feed->filename);
3856

    
3857
                if (ffserver_debug)
3858
                {
3859
                    int j;
3860
                    fprintf(stdout, "Launch commandline: ");
3861
                    for (j = 0; j <= i; j++)
3862
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3863
                    fprintf(stdout, "\n");
3864
                }
3865
            }
3866
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3867
            if (feed) {
3868
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3869
                feed->readonly = 1;
3870
            } else if (stream) {
3871
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3872
            }
3873
        } else if (!strcasecmp(cmd, "File")) {
3874
            if (feed) {
3875
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3876
            } else if (stream)
3877
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3878
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3879
            if (feed) {
3880
                char *p1;
3881
                double fsize;
3882

    
3883
                get_arg(arg, sizeof(arg), &p);
3884
                p1 = arg;
3885
                fsize = strtod(p1, &p1);
3886
                switch(toupper(*p1)) {
3887
                case 'K':
3888
                    fsize *= 1024;
3889
                    break;
3890
                case 'M':
3891
                    fsize *= 1024 * 1024;
3892
                    break;
3893
                case 'G':
3894
                    fsize *= 1024 * 1024 * 1024;
3895
                    break;
3896
                }
3897
                feed->feed_max_size = (int64_t)fsize;
3898
            }
3899
        } else if (!strcasecmp(cmd, "</Feed>")) {
3900
            if (!feed) {
3901
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3902
                        filename, line_num);
3903
                errors++;
3904
            }
3905
            feed = NULL;
3906
        } else if (!strcasecmp(cmd, "<Stream")) {
3907
            /*********************************************/
3908
            /* Stream related options */
3909
            char *q;
3910
            if (stream || feed) {
3911
                fprintf(stderr, "%s:%d: Already in a tag\n",
3912
                        filename, line_num);
3913
            } else {
3914
                const AVClass *class;
3915
                stream = av_mallocz(sizeof(FFStream));
3916
                *last_stream = stream;
3917
                last_stream = &stream->next;
3918

    
3919
                get_arg(stream->filename, sizeof(stream->filename), &p);
3920
                q = strrchr(stream->filename, '>');
3921
                if (*q)
3922
                    *q = '\0';
3923
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3924
                /* fetch avclass so AVOption works
3925
                 * FIXME try to use avcodec_get_context_defaults2
3926
                 * without changing defaults too much */
3927
                avcodec_get_context_defaults(&video_enc);
3928
                class = video_enc.av_class;
3929
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3930
                memset(&video_enc, 0, sizeof(AVCodecContext));
3931
                audio_enc.av_class = class;
3932
                video_enc.av_class = class;
3933
                audio_id = CODEC_ID_NONE;
3934
                video_id = CODEC_ID_NONE;
3935
                if (stream->fmt) {
3936
                    audio_id = stream->fmt->audio_codec;
3937
                    video_id = stream->fmt->video_codec;
3938
                }
3939
            }
3940
        } else if (!strcasecmp(cmd, "Feed")) {
3941
            get_arg(arg, sizeof(arg), &p);
3942
            if (stream) {
3943
                FFStream *sfeed;
3944

    
3945
                sfeed = first_feed;
3946
                while (sfeed != NULL) {
3947
                    if (!strcmp(sfeed->filename, arg))
3948
                        break;
3949
                    sfeed = sfeed->next_feed;
3950
                }
3951
                if (!sfeed)
3952
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3953
                            filename, line_num, arg);
3954
                else
3955
                    stream->feed = sfeed;
3956
            }
3957
        } else if (!strcasecmp(cmd, "Format")) {
3958
            get_arg(arg, sizeof(arg), &p);
3959
            if (stream) {
3960
            if (!strcmp(arg, "status")) {
3961
                stream->stream_type = STREAM_TYPE_STATUS;
3962
                stream->fmt = NULL;
3963
            } else {
3964
                stream->stream_type = STREAM_TYPE_LIVE;
3965
                /* jpeg cannot be used here, so use single frame jpeg */
3966
                if (!strcmp(arg, "jpeg"))
3967
                    strcpy(arg, "mjpeg");
3968
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3969
                if (!stream->fmt) {
3970
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
3971
                            filename, line_num, arg);
3972
                    errors++;
3973
                }
3974
            }
3975
            if (stream->fmt) {
3976
                audio_id = stream->fmt->audio_codec;
3977
                video_id = stream->fmt->video_codec;
3978
            }
3979
            }
3980
        } else if (!strcasecmp(cmd, "InputFormat")) {
3981
            get_arg(arg, sizeof(arg), &p);
3982
            stream->ifmt = av_find_input_format(arg);
3983
            if (!stream->ifmt) {
3984
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
3985
                        filename, line_num, arg);
3986
            }
3987
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3988
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3989
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3990
            } else {
3991
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
3992
                            filename, line_num);
3993
                errors++;
3994
            }
3995
        } else if (!strcasecmp(cmd, "Author")) {
3996
            if (stream)
3997
                get_arg(stream->author, sizeof(stream->author), &p);
3998
        } else if (!strcasecmp(cmd, "Comment")) {
3999
            if (stream)
4000
                get_arg(stream->comment, sizeof(stream->comment), &p);
4001
        } else if (!strcasecmp(cmd, "Copyright")) {
4002
            if (stream)
4003
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4004
        } else if (!strcasecmp(cmd, "Title")) {
4005
            if (stream)
4006
                get_arg(stream->title, sizeof(stream->title), &p);
4007
        } else if (!strcasecmp(cmd, "Preroll")) {
4008
            get_arg(arg, sizeof(arg), &p);
4009
            if (stream)
4010
                stream->prebuffer = atof(arg) * 1000;
4011
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4012
            if (stream)
4013
                stream->send_on_key = 1;
4014
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4015
            get_arg(arg, sizeof(arg), &p);
4016
            audio_id = opt_audio_codec(arg);
4017
            if (audio_id == CODEC_ID_NONE) {
4018
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4019
                        filename, line_num, arg);
4020
                errors++;
4021
            }
4022
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4023
            get_arg(arg, sizeof(arg), &p);
4024
            video_id = opt_video_codec(arg);
4025
            if (video_id == CODEC_ID_NONE) {
4026
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4027
                        filename, line_num, arg);
4028
                errors++;
4029
            }
4030
        } else if (!strcasecmp(cmd, "MaxTime")) {
4031
            get_arg(arg, sizeof(arg), &p);
4032
            if (stream)
4033
                stream->max_time = atof(arg) * 1000;
4034
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4035
            get_arg(arg, sizeof(arg), &p);
4036
            if (stream)
4037
                audio_enc.bit_rate = atoi(arg) * 1000;
4038
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4039
            get_arg(arg, sizeof(arg), &p);
4040
            if (stream)
4041
                audio_enc.channels = atoi(arg);
4042
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4043
            get_arg(arg, sizeof(arg), &p);
4044
            if (stream)
4045
                audio_enc.sample_rate = atoi(arg);
4046
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4047
            get_arg(arg, sizeof(arg), &p);
4048
            if (stream) {
4049
//                audio_enc.quality = atof(arg) * 1000;
4050
            }
4051
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4052
            if (stream) {
4053
                int minrate, maxrate;
4054

    
4055
                get_arg(arg, sizeof(arg), &p);
4056

    
4057
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4058
                    video_enc.rc_min_rate = minrate * 1000;
4059
                    video_enc.rc_max_rate = maxrate * 1000;
4060
                } else {
4061
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4062
                            filename, line_num, arg);
4063
                    errors++;
4064
                }
4065
            }
4066
        } else if (!strcasecmp(cmd, "Debug")) {
4067
            if (stream) {
4068
                get_arg(arg, sizeof(arg), &p);
4069
                video_enc.debug = strtol(arg,0,0);
4070
            }
4071
        } else if (!strcasecmp(cmd, "Strict")) {
4072
            if (stream) {
4073
                get_arg(arg, sizeof(arg), &p);
4074
                video_enc.strict_std_compliance = atoi(arg);
4075
            }
4076
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4077
            if (stream) {
4078
                get_arg(arg, sizeof(arg), &p);
4079
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4080
            }
4081
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4082
            if (stream) {
4083
                get_arg(arg, sizeof(arg), &p);
4084
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4085
            }
4086
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4087
            get_arg(arg, sizeof(arg), &p);
4088
            if (stream) {
4089
                video_enc.bit_rate = atoi(arg) * 1000;
4090
            }
4091
        } else if (!strcasecmp(cmd, "VideoSize")) {
4092
            get_arg(arg, sizeof(arg), &p);
4093
            if (stream) {
4094
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4095
                if ((video_enc.width % 16) != 0 ||
4096
                    (video_enc.height % 16) != 0) {
4097
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4098
                            filename, line_num);
4099
                    errors++;
4100
                }
4101
            }
4102
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4103
            get_arg(arg, sizeof(arg), &p);
4104
            if (stream) {
4105
                AVRational frame_rate;
4106
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4107
                    fprintf(stderr, "Incorrect frame rate\n");
4108
                    errors++;
4109
                } else {
4110
                    video_enc.time_base.num = frame_rate.den;
4111
                    video_enc.time_base.den = frame_rate.num;
4112
                }
4113
            }
4114
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4115
            get_arg(arg, sizeof(arg), &p);
4116
            if (stream)
4117
                video_enc.gop_size = atoi(arg);
4118
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4119
            if (stream)
4120
                video_enc.gop_size = 1;
4121
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4122
            if (stream)
4123
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4124
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4125
            if (stream) {
4126
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4127
                video_enc.flags |= CODEC_FLAG_4MV;
4128
            }
4129
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4130
                   !strcasecmp(cmd, "AVOptionAudio")) {
4131
            char arg2[1024];
4132
            AVCodecContext *avctx;
4133
            int type;
4134
            get_arg(arg, sizeof(arg), &p);
4135
            get_arg(arg2, sizeof(arg2), &p);
4136
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4137
                avctx = &video_enc;
4138
                type = AV_OPT_FLAG_VIDEO_PARAM;
4139
            } else {
4140
                avctx = &audio_enc;
4141
                type = AV_OPT_FLAG_AUDIO_PARAM;
4142
            }
4143
            if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4144
                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4145
                errors++;
4146
            }
4147
        } else if (!strcasecmp(cmd, "VideoTag")) {
4148
            get_arg(arg, sizeof(arg), &p);
4149
            if ((strlen(arg) == 4) && stream)
4150
                video_enc.codec_tag = ff_get_fourcc(arg);
4151
        } else if (!strcasecmp(cmd, "BitExact")) {
4152
            if (stream)
4153
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4154
        } else if (!strcasecmp(cmd, "DctFastint")) {
4155
            if (stream)
4156
                video_enc.dct_algo  = FF_DCT_FASTINT;
4157
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4158
            if (stream)
4159
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4160
        } else if (!strcasecmp(cmd, "Qscale")) {
4161
            get_arg(arg, sizeof(arg), &p);
4162
            if (stream) {
4163
                video_enc.flags |= CODEC_FLAG_QSCALE;
4164
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4165
            }
4166
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4167
            get_arg(arg, sizeof(arg), &p);
4168
            if (stream) {
4169
                video_enc.max_qdiff = atoi(arg);
4170
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4171
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4172
                            filename, line_num);
4173
                    errors++;
4174
                }
4175
            }
4176
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4177
            get_arg(arg, sizeof(arg), &p);
4178
            if (stream) {
4179
                video_enc.qmax = atoi(arg);
4180
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4181
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4182
                            filename, line_num);
4183
                    errors++;
4184
                }
4185
            }
4186
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4187
            get_arg(arg, sizeof(arg), &p);
4188
            if (stream) {
4189
                video_enc.qmin = atoi(arg);
4190
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4191
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4192
                            filename, line_num);
4193
                    errors++;
4194
                }
4195
            }
4196
        } else if (!strcasecmp(cmd, "LumaElim")) {
4197
            get_arg(arg, sizeof(arg), &p);
4198
            if (stream)
4199
                video_enc.luma_elim_threshold = atoi(arg);
4200
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4201
            get_arg(arg, sizeof(arg), &p);
4202
            if (stream)
4203
                video_enc.chroma_elim_threshold = atoi(arg);
4204
        } else if (!strcasecmp(cmd, "LumiMask")) {
4205
            get_arg(arg, sizeof(arg), &p);
4206
            if (stream)
4207
                video_enc.lumi_masking = atof(arg);
4208
        } else if (!strcasecmp(cmd, "DarkMask")) {
4209
            get_arg(arg, sizeof(arg), &p);
4210
            if (stream)
4211
                video_enc.dark_masking = atof(arg);
4212
        } else if (!strcasecmp(cmd, "NoVideo")) {
4213
            video_id = CODEC_ID_NONE;
4214
        } else if (!strcasecmp(cmd, "NoAudio")) {
4215
            audio_id = CODEC_ID_NONE;
4216
        } else if (!strcasecmp(cmd, "ACL")) {
4217
            IPAddressACL acl;
4218

    
4219
            get_arg(arg, sizeof(arg), &p);
4220
            if (strcasecmp(arg, "allow") == 0)
4221
                acl.action = IP_ALLOW;
4222
            else if (strcasecmp(arg, "deny") == 0)
4223
                acl.action = IP_DENY;
4224
            else {
4225
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4226
                        filename, line_num, arg);
4227
                errors++;
4228
            }
4229

    
4230
            get_arg(arg, sizeof(arg), &p);
4231

    
4232
            if (resolve_host(&acl.first, arg) != 0) {
4233
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4234
                        filename, line_num, arg);
4235
                errors++;
4236
            } else
4237
                acl.last = acl.first;
4238

    
4239
            get_arg(arg, sizeof(arg), &p);
4240

    
4241
            if (arg[0]) {
4242
                if (resolve_host(&acl.last, arg) != 0) {
4243
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4244
                            filename, line_num, arg);
4245
                    errors++;
4246
                }
4247
            }
4248

    
4249
            if (!errors) {
4250
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4251
                IPAddressACL **naclp = 0;
4252

    
4253
                acl.next = 0;
4254
                *nacl = acl;
4255

    
4256
                if (stream)
4257
                    naclp = &stream->acl;
4258
                else if (feed)
4259
                    naclp = &feed->acl;
4260
                else {
4261
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4262
                            filename, line_num);
4263
                    errors++;
4264
                }
4265

    
4266
                if (naclp) {
4267
                    while (*naclp)
4268
                        naclp = &(*naclp)->next;
4269

    
4270
                    *naclp = nacl;
4271
                }
4272
            }
4273
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4274
            get_arg(arg, sizeof(arg), &p);
4275
            if (stream) {
4276
                av_freep(&stream->rtsp_option);
4277
                stream->rtsp_option = av_strdup(arg);
4278
            }
4279
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4280
            get_arg(arg, sizeof(arg), &p);
4281
            if (stream) {
4282
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4283
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4284
                            filename, line_num, arg);
4285
                    errors++;
4286
                }
4287
                stream->is_multicast = 1;
4288
                stream->loop = 1; /* default is looping */
4289
            }
4290
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4291
            get_arg(arg, sizeof(arg), &p);
4292
            if (stream)
4293
                stream->multicast_port = atoi(arg);
4294
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4295
            get_arg(arg, sizeof(arg), &p);
4296
            if (stream)
4297
                stream->multicast_ttl = atoi(arg);
4298
        } else if (!strcasecmp(cmd, "NoLoop")) {
4299
            if (stream)
4300
                stream->loop = 0;
4301
        } else if (!strcasecmp(cmd, "</Stream>")) {
4302
            if (!stream) {
4303
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4304
                        filename, line_num);
4305
                errors++;
4306
            } else {
4307
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4308
                    if (audio_id != CODEC_ID_NONE) {
4309
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4310
                        audio_enc.codec_id = audio_id;
4311
                        add_codec(stream, &audio_enc);
4312
                    }
4313
                    if (video_id != CODEC_ID_NONE) {
4314
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4315
                        video_enc.codec_id = video_id;
4316
                        add_codec(stream, &video_enc);
4317
                    }
4318
                }
4319
                stream = NULL;
4320
            }
4321
        } else if (!strcasecmp(cmd, "<Redirect")) {
4322
            /*********************************************/
4323
            char *q;
4324
            if (stream || feed || redirect) {
4325
                fprintf(stderr, "%s:%d: Already in a tag\n",
4326
                        filename, line_num);
4327
                errors++;
4328
            } else {
4329
                redirect = av_mallocz(sizeof(FFStream));
4330
                *last_stream = redirect;
4331
                last_stream = &redirect->next;
4332

    
4333
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4334
                q = strrchr(redirect->filename, '>');
4335
                if (*q)
4336
                    *q = '\0';
4337
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4338
            }
4339
        } else if (!strcasecmp(cmd, "URL")) {
4340
            if (redirect)
4341
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4342
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4343
            if (!redirect) {
4344
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4345
                        filename, line_num);
4346
                errors++;
4347
            } else {
4348
                if (!redirect->feed_filename[0]) {
4349
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4350
                            filename, line_num);
4351
                    errors++;
4352
                }
4353
                redirect = NULL;
4354
            }
4355
        } else if (!strcasecmp(cmd, "LoadModule")) {
4356
            get_arg(arg, sizeof(arg), &p);
4357
#ifdef HAVE_DLOPEN
4358
            load_module(arg);
4359
#else
4360
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4361
                    filename, line_num, arg);
4362
            errors++;
4363
#endif
4364
        } else {
4365
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4366
                    filename, line_num, cmd);
4367
            errors++;
4368
        }
4369
    }
4370

    
4371
    fclose(f);
4372
    if (errors)
4373
        return -1;
4374
    else
4375
        return 0;
4376
}
4377

    
4378
static void handle_child_exit(int sig)
4379
{
4380
    pid_t pid;
4381
    int status;
4382

    
4383
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4384
        FFStream *feed;
4385

    
4386
        for (feed = first_feed; feed; feed = feed->next) {
4387
            if (feed->pid == pid) {
4388
                int uptime = time(0) - feed->pid_start;
4389

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

    
4393
                if (uptime < 30)
4394
                    /* Turn off any more restarts */
4395
                    feed->child_argv = 0;
4396
            }
4397
        }
4398
    }
4399

    
4400
    need_to_start_children = 1;
4401
}
4402

    
4403
static void opt_debug()
4404
{
4405
    ffserver_debug = 1;
4406
    ffserver_daemon = 0;
4407
    logfilename[0] = '-';
4408
}
4409

    
4410
static void opt_show_help(void)
4411
{
4412
    printf("usage: ffserver [options]\n"
4413
           "Hyper fast multi format Audio/Video streaming server\n");
4414
    printf("\n");
4415
    show_help_options(options, "Main options:\n", 0, 0);
4416
}
4417

    
4418
static const OptionDef options[] = {
4419
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4420
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4421
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4422
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4423
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4424
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4425
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4426
    { NULL },
4427
};
4428

    
4429
int main(int argc, char **argv)
4430
{
4431
    struct sigaction sigact;
4432

    
4433
    av_register_all();
4434

    
4435
    show_banner();
4436

    
4437
    config_filename = "/etc/ffserver.conf";
4438

    
4439
    my_program_name = argv[0];
4440
    my_program_dir = getcwd(0, 0);
4441
    ffserver_daemon = 1;
4442

    
4443
    parse_options(argc, argv, options, NULL);
4444

    
4445
    unsetenv("http_proxy");             /* Kill the http_proxy */
4446

    
4447
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4448

    
4449
    /* address on which the server will handle HTTP connections */
4450
    my_http_addr.sin_family = AF_INET;
4451
    my_http_addr.sin_port = htons (8080);
4452
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4453

    
4454
    /* address on which the server will handle RTSP connections */
4455
    my_rtsp_addr.sin_family = AF_INET;
4456
    my_rtsp_addr.sin_port = htons (5454);
4457
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4458

    
4459
    nb_max_connections = 5;
4460
    max_bandwidth = 1000;
4461
    first_stream = NULL;
4462

    
4463
    memset(&sigact, 0, sizeof(sigact));
4464
    sigact.sa_handler = handle_child_exit;
4465
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4466
    sigaction(SIGCHLD, &sigact, 0);
4467

    
4468
    if (parse_ffconfig(config_filename) < 0) {
4469
        fprintf(stderr, "Incorrect config file - exiting.\n");
4470
        exit(1);
4471
    }
4472

    
4473
    build_file_streams();
4474

    
4475
    build_feed_streams();
4476

    
4477
    compute_bandwidth();
4478

    
4479
    /* put the process in background and detach it from its TTY */
4480
    if (ffserver_daemon) {
4481
        int pid;
4482

    
4483
        pid = fork();
4484
        if (pid < 0) {
4485
            perror("fork");
4486
            exit(1);
4487
        } else if (pid > 0) {
4488
            /* parent : exit */
4489
            exit(0);
4490
        } else {
4491
            /* child */
4492
            setsid();
4493
            chdir("/");
4494
            close(0);
4495
            open("/dev/null", O_RDWR);
4496
            if (strcmp(logfilename, "-") != 0) {
4497
                close(1);
4498
                dup(0);
4499
            }
4500
            close(2);
4501
            dup(0);
4502
        }
4503
    }
4504

    
4505
    /* signal init */
4506
    signal(SIGPIPE, SIG_IGN);
4507

    
4508
    /* open log file if needed */
4509
    if (logfilename[0] != '\0') {
4510
        if (!strcmp(logfilename, "-"))
4511
            logfile = stdout;
4512
        else
4513
            logfile = fopen(logfilename, "a");
4514
    }
4515

    
4516
    if (http_server() < 0) {
4517
        http_log("Could not start server\n");
4518
        exit(1);
4519
    }
4520

    
4521
    return 0;
4522
}