Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 180b7026

History | View | Annotate | Download (148 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

    
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
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
    int 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_stats(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 int max_bandwidth;
299
static int 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
                fprintf(stderr, "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)
396
                        dup2(i, 0);
397
                    dup2(i, 1);
398
                    dup2(i, 2);
399
                    if (i)
400
                        close(i);
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
                fprintf(stderr, "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
                    fprintf(stderr, "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
        return;
659
    ff_socket_nonblock(fd, 1);
660

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

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

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

    
679
    c->next = first_http_ctx;
680
    first_http_ctx = c;
681
    nb_connections++;
682

    
683
    start_wait_request(c, is_rtsp);
684

    
685
    return;
686

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

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

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

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

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

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

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

    
748
    ctx = &c->fmt_ctx;
749

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

    
760
    for(i=0; i<ctx->nb_streams; i++)
761
        av_free(ctx->streams[i]);
762

    
763
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
764
        current_bandwidth -= c->stream->bandwidth;
765

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

    
772
    av_freep(&c->pb_buffer);
773
    av_freep(&c->packet_buffer);
774
    av_free(c->buffer);
775
    av_free(c);
776
    nb_connections--;
777
}
778

    
779
static int handle_connection(HTTPContext *c)
780
{
781
    int len, ret;
782

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

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

    
826
    case HTTPSTATE_SEND_HEADER:
827
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
828
            return -1;
829

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

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

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

    
892
        /* nothing to do, we'll be waken up by incoming feed packets */
893
        break;
894

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

    
956
static int extract_rates(char *rates, int ratelen, const char *request)
957
{
958
    const char *p;
959

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

    
964
            while (*q && *q != '\n' && isspace(*q))
965
                q++;
966

    
967
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
968
                int stream_no;
969
                int rate_no;
970

    
971
                q += 20;
972

    
973
                memset(rates, 0xff, ratelen);
974

    
975
                while (1) {
976
                    while (*q && *q != '\n' && *q != ':')
977
                        q++;
978

    
979
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
980
                        break;
981

    
982
                    stream_no--;
983
                    if (stream_no < ratelen && stream_no >= 0)
984
                        rates[stream_no] = rate_no;
985

    
986
                    while (*q && *q != '\n' && !isspace(*q))
987
                        q++;
988
                }
989

    
990
                return 1;
991
            }
992
        }
993
        p = strchr(p, '\n');
994
        if (!p)
995
            break;
996

    
997
        p++;
998
    }
999

    
1000
    return 0;
1001
}
1002

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

    
1009
    for (i = 0; i < feed->nb_streams; i++) {
1010
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1011

    
1012
        if (feed_codec->codec_id != codec->codec_id ||
1013
            feed_codec->sample_rate != codec->sample_rate ||
1014
            feed_codec->width != codec->width ||
1015
            feed_codec->height != codec->height)
1016
            continue;
1017

    
1018
        /* Potential stream */
1019

    
1020
        /* We want the fastest stream less than bit_rate, or the slowest
1021
         * faster than bit_rate
1022
         */
1023

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

    
1037
    return best;
1038
}
1039

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

    
1046
    /* Not much we can do for a feed */
1047
    if (!req->feed)
1048
        return 0;
1049

    
1050
    for (i = 0; i < req->nb_streams; i++) {
1051
        AVCodecContext *codec = req->streams[i]->codec;
1052

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

    
1071
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1072
            action_required = 1;
1073
    }
1074

    
1075
    return action_required;
1076
}
1077

    
1078

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

    
1086
        /* Now update the stream */
1087
    }
1088
    c->switch_feed_streams[i] = -1;
1089
}
1090

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

    
1102
static void get_word(char *buf, int buf_size, const char **pp)
1103
{
1104
    const char *p;
1105
    char *q;
1106

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

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

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

    
1133
    /* Nothing matched, so return not the last action */
1134
    return (last_action == IP_DENY) ? 1 : 0;
1135
}
1136

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

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

    
1163
enum RedirType {
1164
    REDIR_NONE,
1165
    REDIR_ASX,
1166
    REDIR_RAM,
1167
    REDIR_ASF,
1168
    REDIR_RTSP,
1169
    REDIR_SDP,
1170
};
1171

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

    
1188
    p = c->buffer;
1189
    get_word(cmd, sizeof(cmd), (const char **)&p);
1190
    av_strlcpy(c->method, cmd, sizeof(c->method));
1191

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

    
1199
    get_word(url, sizeof(url), (const char **)&p);
1200
    av_strlcpy(c->url, url, sizeof(c->url));
1201

    
1202
    get_word(protocol, sizeof(protocol), (const char **)&p);
1203
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1204
        return -1;
1205

    
1206
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1207

    
1208
    if (ffserver_debug)
1209
        http_log("New connection: %s %s\n", cmd, url);
1210

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

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

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

    
1232
        p++;
1233
    }
1234

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

    
1254
    // "redirect" / request to index.html
1255
    if (!strlen(filename))
1256
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1257

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

    
1269
    c->stream = stream;
1270
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1271
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1272

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

    
1284
        /* prepare output buffer */
1285
        c->buffer_ptr = c->buffer;
1286
        c->buffer_end = q;
1287
        c->state = HTTPSTATE_SEND_HEADER;
1288
        return 0;
1289
    }
1290

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

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

    
1307
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1308
        current_bandwidth += stream->bandwidth;
1309

    
1310
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1311
        c->http_error = 200;
1312
        q = c->buffer;
1313
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1314
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1315
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1316
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1317
        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");
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1319
            current_bandwidth, max_bandwidth);
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1321

    
1322
        /* prepare output buffer */
1323
        c->buffer_ptr = c->buffer;
1324
        c->buffer_end = q;
1325
        c->state = HTTPSTATE_SEND_HEADER;
1326
        return 0;
1327
    }
1328

    
1329
    if (redir_type != REDIR_NONE) {
1330
        char *hostinfo = 0;
1331

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

    
1341
            p++;
1342
        }
1343

    
1344
        if (hostinfo) {
1345
            char *eoh;
1346
            char hostbuf[260];
1347

    
1348
            while (isspace(*hostinfo))
1349
                hostinfo++;
1350

    
1351
            eoh = strchr(hostinfo, '\n');
1352
            if (eoh) {
1353
                if (eoh[-1] == '\r')
1354
                    eoh--;
1355

    
1356
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1357
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1358
                    hostbuf[eoh - hostinfo] = 0;
1359

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

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

    
1416
                            len = sizeof(my_addr);
1417
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1418

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

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

    
1445
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1446
        goto send_error;
1447
    }
1448

    
1449
    stream->conns_served++;
1450

    
1451
    /* XXX: add there authenticate and IP match */
1452

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

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

    
1473
                p++;
1474
            }
1475

    
1476
            if (logline) {
1477
                char *eol = strchr(logline, '\n');
1478

    
1479
                logline += 17;
1480

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

    
1489
#ifdef DEBUG_WMP
1490
            http_log("\nGot request:\n%s\n", c->buffer);
1491
#endif
1492

    
1493
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1494
                HTTPContext *wmpc;
1495

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

    
1502
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1503
                    wmpc->switch_pending = 1;
1504
            }
1505

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

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

    
1524
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1525
        goto send_stats;
1526

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

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

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

    
1545
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1546

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

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

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

    
1582
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1583
{
1584
    static const char *suffix = " kMGTP";
1585
    const char *s;
1586

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

    
1589
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1590
}
1591

    
1592
static void compute_stats(HTTPContext *c)
1593
{
1594
    HTTPContext *c1;
1595
    FFStream *stream;
1596
    char *p;
1597
    time_t ti;
1598
    int i, len;
1599
    ByteIOContext *pb;
1600

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

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

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

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

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

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

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

    
1719
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1720
                {
1721
                    FILE *pid_stat;
1722
                    char ps_cmd[64];
1723

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

    
1729
                    pid_stat = popen(ps_cmd, "r");
1730
                    if (pid_stat) {
1731
                        char cpuperc[10];
1732
                        char cpuused[64];
1733

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

    
1744
                url_fprintf(pb, "<p>");
1745
            }
1746
            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");
1747

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

    
1754
                parameters[0] = 0;
1755

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

    
1774
        }
1775
        stream = stream->next;
1776
    }
1777

    
1778
#if 0
1779
    {
1780
        float avg;
1781
        AVCodecContext *enc;
1782
        char buf[1024];
1783

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

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

    
1808
    /* connection status */
1809
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1810

    
1811
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1812
                 nb_connections, nb_max_connections);
1813

    
1814
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1815
                 current_bandwidth, max_bandwidth);
1816

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

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

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

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

    
1860
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1861
    c->buffer_ptr = c->pb_buffer;
1862
    c->buffer_end = c->pb_buffer + len;
1863
}
1864

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

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

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

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

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

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

    
1937
    /* open each parser */
1938
    for(i=0;i<s->nb_streams;i++)
1939
        open_parser(s, i);
1940

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

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

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

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

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

    
1984

    
1985
static int http_prepare_data(HTTPContext *c)
1986
{
1987
    int i, len, ret;
1988
    AVFormatContext *ctx;
1989

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

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

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

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

    
2033
        av_set_parameters(&c->fmt_ctx, NULL);
2034
        if (av_write_header(&c->fmt_ctx) < 0) {
2035
            http_log("Error writing output header\n");
2036
            return -1;
2037
        }
2038

    
2039
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2040
        c->buffer_ptr = c->pb_buffer;
2041
        c->buffer_end = c->pb_buffer + len;
2042

    
2043
        c->state = HTTPSTATE_SEND_DATA;
2044
        c->last_packet_sent = 0;
2045
        break;
2046
    case HTTPSTATE_SEND_DATA:
2047
        /* find a new packet */
2048
        /* read a packet from the input stream */
2049
        if (c->stream->feed)
2050
            ffm_set_write_index(c->fmt_in,
2051
                                c->stream->feed->feed_write_index,
2052
                                c->stream->feed->feed_size);
2053

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

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

    
2151
                    if (c->is_packetized) {
2152
                        int max_packet_size;
2153
                        if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2154
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2155
                        else
2156
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2157
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2158
                    } else {
2159
                        ret = url_open_dyn_buf(&ctx->pb);
2160
                    }
2161
                    if (ret < 0) {
2162
                        /* XXX: potential leak */
2163
                        return -1;
2164
                    }
2165
                    c->fmt_ctx.pb->is_streamed = 1;
2166
                    if (pkt.dts != AV_NOPTS_VALUE)
2167
                        pkt.dts = av_rescale_q(pkt.dts,
2168
                                               c->fmt_in->streams[source_index]->time_base,
2169
                                               ctx->streams[pkt.stream_index]->time_base);
2170
                    if (pkt.pts != AV_NOPTS_VALUE)
2171
                        pkt.pts = av_rescale_q(pkt.pts,
2172
                                               c->fmt_in->streams[source_index]->time_base,
2173
                                               ctx->streams[pkt.stream_index]->time_base);
2174
                    if (av_write_frame(ctx, &pkt) < 0) {
2175
                        http_log("Error writing frame to output\n");
2176
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2177
                    }
2178

    
2179
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2180
                    c->cur_frame_bytes = len;
2181
                    c->buffer_ptr = c->pb_buffer;
2182
                    c->buffer_end = c->pb_buffer + len;
2183

    
2184
                    codec->frame_number++;
2185
                    if (len == 0) {
2186
                        av_free_packet(&pkt);
2187
                        goto redo;
2188
                    }
2189
                }
2190
                av_free_packet(&pkt);
2191
            }
2192
        }
2193
        break;
2194
    default:
2195
    case HTTPSTATE_SEND_DATA_TRAILER:
2196
        /* last packet test ? */
2197
        if (c->last_packet_sent || c->is_packetized)
2198
            return -1;
2199
        ctx = &c->fmt_ctx;
2200
        /* prepare header */
2201
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2202
            /* XXX: potential leak */
2203
            return -1;
2204
        }
2205
        c->fmt_ctx.pb->is_streamed = 1;
2206
        av_write_trailer(ctx);
2207
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2208
        c->buffer_ptr = c->pb_buffer;
2209
        c->buffer_end = c->pb_buffer + len;
2210

    
2211
        c->last_packet_sent = 1;
2212
        break;
2213
    }
2214
    return 0;
2215
}
2216

    
2217
/* should convert the format at the same time */
2218
/* send data starting at c->buffer_ptr to the output connection
2219
   (either UDP or TCP connection) */
2220
static int http_send_data(HTTPContext *c)
2221
{
2222
    int len, ret;
2223

    
2224
    for(;;) {
2225
        if (c->buffer_ptr >= c->buffer_end) {
2226
            ret = http_prepare_data(c);
2227
            if (ret < 0)
2228
                return -1;
2229
            else if (ret != 0)
2230
                /* state change requested */
2231
                break;
2232
        } else {
2233
            if (c->is_packetized) {
2234
                /* RTP data output */
2235
                len = c->buffer_end - c->buffer_ptr;
2236
                if (len < 4) {
2237
                    /* fail safe - should never happen */
2238
                fail1:
2239
                    c->buffer_ptr = c->buffer_end;
2240
                    return 0;
2241
                }
2242
                len = (c->buffer_ptr[0] << 24) |
2243
                    (c->buffer_ptr[1] << 16) |
2244
                    (c->buffer_ptr[2] << 8) |
2245
                    (c->buffer_ptr[3]);
2246
                if (len > (c->buffer_end - c->buffer_ptr))
2247
                    goto fail1;
2248
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2249
                    /* nothing to send yet: we can wait */
2250
                    return 0;
2251
                }
2252

    
2253
                c->data_count += len;
2254
                update_datarate(&c->datarate, c->data_count);
2255
                if (c->stream)
2256
                    c->stream->bytes_served += len;
2257

    
2258
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2259
                    /* RTP packets are sent inside the RTSP TCP connection */
2260
                    ByteIOContext *pb;
2261
                    int interleaved_index, size;
2262
                    uint8_t header[4];
2263
                    HTTPContext *rtsp_c;
2264

    
2265
                    rtsp_c = c->rtsp_c;
2266
                    /* if no RTSP connection left, error */
2267
                    if (!rtsp_c)
2268
                        return -1;
2269
                    /* if already sending something, then wait. */
2270
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2271
                        break;
2272
                    if (url_open_dyn_buf(&pb) < 0)
2273
                        goto fail1;
2274
                    interleaved_index = c->packet_stream_index * 2;
2275
                    /* RTCP packets are sent at odd indexes */
2276
                    if (c->buffer_ptr[1] == 200)
2277
                        interleaved_index++;
2278
                    /* write RTSP TCP header */
2279
                    header[0] = '$';
2280
                    header[1] = interleaved_index;
2281
                    header[2] = len >> 8;
2282
                    header[3] = len;
2283
                    put_buffer(pb, header, 4);
2284
                    /* write RTP packet data */
2285
                    c->buffer_ptr += 4;
2286
                    put_buffer(pb, c->buffer_ptr, len);
2287
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2288
                    /* prepare asynchronous TCP sending */
2289
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2290
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2291
                    c->buffer_ptr += len;
2292

    
2293
                    /* send everything we can NOW */
2294
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2295
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2296
                    if (len > 0)
2297
                        rtsp_c->packet_buffer_ptr += len;
2298
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2299
                        /* if we could not send all the data, we will
2300
                           send it later, so a new state is needed to
2301
                           "lock" the RTSP TCP connection */
2302
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2303
                        break;
2304
                    } else
2305
                        /* all data has been sent */
2306
                        av_freep(&c->packet_buffer);
2307
                } else {
2308
                    /* send RTP packet directly in UDP */
2309
                    c->buffer_ptr += 4;
2310
                    url_write(c->rtp_handles[c->packet_stream_index],
2311
                              c->buffer_ptr, len);
2312
                    c->buffer_ptr += len;
2313
                    /* here we continue as we can send several packets per 10 ms slot */
2314
                }
2315
            } else {
2316
                /* TCP data output */
2317
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2318
                if (len < 0) {
2319
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2320
                        ff_neterrno() != FF_NETERROR(EINTR))
2321
                        /* error : close connection */
2322
                        return -1;
2323
                    else
2324
                        return 0;
2325
                } else
2326
                    c->buffer_ptr += len;
2327

    
2328
                c->data_count += len;
2329
                update_datarate(&c->datarate, c->data_count);
2330
                if (c->stream)
2331
                    c->stream->bytes_served += len;
2332
                break;
2333
            }
2334
        }
2335
    } /* for(;;) */
2336
    return 0;
2337
}
2338

    
2339
static int http_start_receive_data(HTTPContext *c)
2340
{
2341
    int fd;
2342

    
2343
    if (c->stream->feed_opened)
2344
        return -1;
2345

    
2346
    /* Don't permit writing to this one */
2347
    if (c->stream->readonly)
2348
        return -1;
2349

    
2350
    /* open feed */
2351
    fd = open(c->stream->feed_filename, O_RDWR);
2352
    if (fd < 0) {
2353
        http_log("Error opening feeder file: %s\n", strerror(errno));
2354
        return -1;
2355
    }
2356
    c->feed_fd = fd;
2357

    
2358
    c->stream->feed_write_index = ffm_read_write_index(fd);
2359
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2360
    lseek(fd, 0, SEEK_SET);
2361

    
2362
    /* init buffer input */
2363
    c->buffer_ptr = c->buffer;
2364
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2365
    c->stream->feed_opened = 1;
2366
    return 0;
2367
}
2368

    
2369
static int http_receive_data(HTTPContext *c)
2370
{
2371
    HTTPContext *c1;
2372

    
2373
    if (c->buffer_end > c->buffer_ptr) {
2374
        int len;
2375

    
2376
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2377
        if (len < 0) {
2378
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2379
                ff_neterrno() != FF_NETERROR(EINTR))
2380
                /* error : close connection */
2381
                goto fail;
2382
        } else if (len == 0)
2383
            /* end of connection : close it */
2384
            goto fail;
2385
        else {
2386
            c->buffer_ptr += len;
2387
            c->data_count += len;
2388
            update_datarate(&c->datarate, c->data_count);
2389
        }
2390
    }
2391

    
2392
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2393
        if (c->buffer[0] != 'f' ||
2394
            c->buffer[1] != 'm') {
2395
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2396
            goto fail;
2397
        }
2398
    }
2399

    
2400
    if (c->buffer_ptr >= c->buffer_end) {
2401
        FFStream *feed = c->stream;
2402
        /* a packet has been received : write it in the store, except
2403
           if header */
2404
        if (c->data_count > FFM_PACKET_SIZE) {
2405

    
2406
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2407
            /* XXX: use llseek or url_seek */
2408
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2409
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2410
                http_log("Error writing to feed file: %s\n", strerror(errno));
2411
                goto fail;
2412
            }
2413

    
2414
            feed->feed_write_index += FFM_PACKET_SIZE;
2415
            /* update file size */
2416
            if (feed->feed_write_index > c->stream->feed_size)
2417
                feed->feed_size = feed->feed_write_index;
2418

    
2419
            /* handle wrap around if max file size reached */
2420
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2421
                feed->feed_write_index = FFM_PACKET_SIZE;
2422

    
2423
            /* write index */
2424
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2425

    
2426
            /* wake up any waiting connections */
2427
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2428
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2429
                    c1->stream->feed == c->stream->feed)
2430
                    c1->state = HTTPSTATE_SEND_DATA;
2431
            }
2432
        } else {
2433
            /* We have a header in our hands that contains useful data */
2434
            AVFormatContext s;
2435
            AVInputFormat *fmt_in;
2436
            int i;
2437

    
2438
            memset(&s, 0, sizeof(s));
2439

    
2440
            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2441
            s.pb->is_streamed = 1;
2442

    
2443
            /* use feed output format name to find corresponding input format */
2444
            fmt_in = av_find_input_format(feed->fmt->name);
2445
            if (!fmt_in)
2446
                goto fail;
2447

    
2448
            if (fmt_in->priv_data_size > 0) {
2449
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2450
                if (!s.priv_data)
2451
                    goto fail;
2452
            } else
2453
                s.priv_data = NULL;
2454

    
2455
            if (fmt_in->read_header(&s, 0) < 0) {
2456
                av_freep(&s.priv_data);
2457
                goto fail;
2458
            }
2459

    
2460
            /* Now we have the actual streams */
2461
            if (s.nb_streams != feed->nb_streams) {
2462
                av_freep(&s.priv_data);
2463
                goto fail;
2464
            }
2465
            for (i = 0; i < s.nb_streams; i++)
2466
                memcpy(feed->streams[i]->codec,
2467
                       s.streams[i]->codec, sizeof(AVCodecContext));
2468
            av_freep(&s.priv_data);
2469
        }
2470
        c->buffer_ptr = c->buffer;
2471
    }
2472

    
2473
    return 0;
2474
 fail:
2475
    c->stream->feed_opened = 0;
2476
    close(c->feed_fd);
2477
    /* wake up any waiting connections to stop waiting for feed */
2478
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2479
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2480
            c1->stream->feed == c->stream->feed)
2481
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2482
    }
2483
    return -1;
2484
}
2485

    
2486
/********************************************************************/
2487
/* RTSP handling */
2488

    
2489
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2490
{
2491
    const char *str;
2492
    time_t ti;
2493
    char *p;
2494
    char buf2[32];
2495

    
2496
    switch(error_number) {
2497
    case RTSP_STATUS_OK:
2498
        str = "OK";
2499
        break;
2500
    case RTSP_STATUS_METHOD:
2501
        str = "Method Not Allowed";
2502
        break;
2503
    case RTSP_STATUS_BANDWIDTH:
2504
        str = "Not Enough Bandwidth";
2505
        break;
2506
    case RTSP_STATUS_SESSION:
2507
        str = "Session Not Found";
2508
        break;
2509
    case RTSP_STATUS_STATE:
2510
        str = "Method Not Valid in This State";
2511
        break;
2512
    case RTSP_STATUS_AGGREGATE:
2513
        str = "Aggregate operation not allowed";
2514
        break;
2515
    case RTSP_STATUS_ONLY_AGGREGATE:
2516
        str = "Only aggregate operation allowed";
2517
        break;
2518
    case RTSP_STATUS_TRANSPORT:
2519
        str = "Unsupported transport";
2520
        break;
2521
    case RTSP_STATUS_INTERNAL:
2522
        str = "Internal Server Error";
2523
        break;
2524
    case RTSP_STATUS_SERVICE:
2525
        str = "Service Unavailable";
2526
        break;
2527
    case RTSP_STATUS_VERSION:
2528
        str = "RTSP Version not supported";
2529
        break;
2530
    default:
2531
        str = "Unknown Error";
2532
        break;
2533
    }
2534

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

    
2538
    /* output GMT time */
2539
    ti = time(NULL);
2540
    p = ctime(&ti);
2541
    strcpy(buf2, p);
2542
    p = buf2 + strlen(p) - 1;
2543
    if (*p == '\n')
2544
        *p = '\0';
2545
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2546
}
2547

    
2548
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2549
{
2550
    rtsp_reply_header(c, error_number);
2551
    url_fprintf(c->pb, "\r\n");
2552
}
2553

    
2554
static int rtsp_parse_request(HTTPContext *c)
2555
{
2556
    const char *p, *p1, *p2;
2557
    char cmd[32];
2558
    char url[1024];
2559
    char protocol[32];
2560
    char line[1024];
2561
    int len;
2562
    RTSPHeader header1, *header = &header1;
2563

    
2564
    c->buffer_ptr[0] = '\0';
2565
    p = c->buffer;
2566

    
2567
    get_word(cmd, sizeof(cmd), &p);
2568
    get_word(url, sizeof(url), &p);
2569
    get_word(protocol, sizeof(protocol), &p);
2570

    
2571
    av_strlcpy(c->method, cmd, sizeof(c->method));
2572
    av_strlcpy(c->url, url, sizeof(c->url));
2573
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2574

    
2575
    if (url_open_dyn_buf(&c->pb) < 0) {
2576
        /* XXX: cannot do more */
2577
        c->pb = NULL; /* safety */
2578
        return -1;
2579
    }
2580

    
2581
    /* check version name */
2582
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2583
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2584
        goto the_end;
2585
    }
2586

    
2587
    /* parse each header line */
2588
    memset(header, 0, sizeof(RTSPHeader));
2589
    /* skip to next line */
2590
    while (*p != '\n' && *p != '\0')
2591
        p++;
2592
    if (*p == '\n')
2593
        p++;
2594
    while (*p != '\0') {
2595
        p1 = strchr(p, '\n');
2596
        if (!p1)
2597
            break;
2598
        p2 = p1;
2599
        if (p2 > p && p2[-1] == '\r')
2600
            p2--;
2601
        /* skip empty line */
2602
        if (p2 == p)
2603
            break;
2604
        len = p2 - p;
2605
        if (len > sizeof(line) - 1)
2606
            len = sizeof(line) - 1;
2607
        memcpy(line, p, len);
2608
        line[len] = '\0';
2609
        rtsp_parse_line(header, line);
2610
        p = p1 + 1;
2611
    }
2612

    
2613
    /* handle sequence number */
2614
    c->seq = header->seq;
2615

    
2616
    if (!strcmp(cmd, "DESCRIBE"))
2617
        rtsp_cmd_describe(c, url);
2618
    else if (!strcmp(cmd, "OPTIONS"))
2619
        rtsp_cmd_options(c, url);
2620
    else if (!strcmp(cmd, "SETUP"))
2621
        rtsp_cmd_setup(c, url, header);
2622
    else if (!strcmp(cmd, "PLAY"))
2623
        rtsp_cmd_play(c, url, header);
2624
    else if (!strcmp(cmd, "PAUSE"))
2625
        rtsp_cmd_pause(c, url, header);
2626
    else if (!strcmp(cmd, "TEARDOWN"))
2627
        rtsp_cmd_teardown(c, url, header);
2628
    else
2629
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2630

    
2631
 the_end:
2632
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2633
    c->pb = NULL; /* safety */
2634
    if (len < 0) {
2635
        /* XXX: cannot do more */
2636
        return -1;
2637
    }
2638
    c->buffer_ptr = c->pb_buffer;
2639
    c->buffer_end = c->pb_buffer + len;
2640
    c->state = RTSPSTATE_SEND_REPLY;
2641
    return 0;
2642
}
2643

    
2644
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2645
                                   struct in_addr my_ip)
2646
{
2647
    AVFormatContext *avc;
2648
    AVStream avs[MAX_STREAMS];
2649
    int i;
2650

    
2651
    avc =  av_alloc_format_context();
2652
    if (avc == NULL) {
2653
        return -1;
2654
    }
2655
    if (stream->title[0] != 0) {
2656
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2657
    } else {
2658
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2659
    }
2660
    avc->nb_streams = stream->nb_streams;
2661
    if (stream->is_multicast) {
2662
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2663
                 inet_ntoa(stream->multicast_ip),
2664
                 stream->multicast_port, stream->multicast_ttl);
2665
    }
2666

    
2667
    for(i = 0; i < stream->nb_streams; i++) {
2668
        avc->streams[i] = &avs[i];
2669
        avc->streams[i]->codec = stream->streams[i]->codec;
2670
    }
2671
    *pbuffer = av_mallocz(2048);
2672
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2673
    av_free(avc);
2674

    
2675
    return strlen(*pbuffer);
2676
}
2677

    
2678
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2679
{
2680
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2681
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2682
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2683
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2684
    url_fprintf(c->pb, "\r\n");
2685
}
2686

    
2687
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2688
{
2689
    FFStream *stream;
2690
    char path1[1024];
2691
    const char *path;
2692
    uint8_t *content;
2693
    int content_length, len;
2694
    struct sockaddr_in my_addr;
2695

    
2696
    /* find which url is asked */
2697
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2698
    path = path1;
2699
    if (*path == '/')
2700
        path++;
2701

    
2702
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2703
        if (!stream->is_feed &&
2704
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2705
            !strcmp(path, stream->filename)) {
2706
            goto found;
2707
        }
2708
    }
2709
    /* no stream found */
2710
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2711
    return;
2712

    
2713
 found:
2714
    /* prepare the media description in sdp format */
2715

    
2716
    /* get the host IP */
2717
    len = sizeof(my_addr);
2718
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2719
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2720
    if (content_length < 0) {
2721
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2722
        return;
2723
    }
2724
    rtsp_reply_header(c, RTSP_STATUS_OK);
2725
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2726
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2727
    url_fprintf(c->pb, "\r\n");
2728
    put_buffer(c->pb, content, content_length);
2729
}
2730

    
2731
static HTTPContext *find_rtp_session(const char *session_id)
2732
{
2733
    HTTPContext *c;
2734

    
2735
    if (session_id[0] == '\0')
2736
        return NULL;
2737

    
2738
    for(c = first_http_ctx; c != NULL; c = c->next) {
2739
        if (!strcmp(c->session_id, session_id))
2740
            return c;
2741
    }
2742
    return NULL;
2743
}
2744

    
2745
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2746
{
2747
    RTSPTransportField *th;
2748
    int i;
2749

    
2750
    for(i=0;i<h->nb_transports;i++) {
2751
        th = &h->transports[i];
2752
        if (th->protocol == protocol)
2753
            return th;
2754
    }
2755
    return NULL;
2756
}
2757

    
2758
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2759
                           RTSPHeader *h)
2760
{
2761
    FFStream *stream;
2762
    int stream_index, port;
2763
    char buf[1024];
2764
    char path1[1024];
2765
    const char *path;
2766
    HTTPContext *rtp_c;
2767
    RTSPTransportField *th;
2768
    struct sockaddr_in dest_addr;
2769
    RTSPActionServerSetup setup;
2770

    
2771
    /* find which url is asked */
2772
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2773
    path = path1;
2774
    if (*path == '/')
2775
        path++;
2776

    
2777
    /* now check each stream */
2778
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2779
        if (!stream->is_feed &&
2780
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2781
            /* accept aggregate filenames only if single stream */
2782
            if (!strcmp(path, stream->filename)) {
2783
                if (stream->nb_streams != 1) {
2784
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2785
                    return;
2786
                }
2787
                stream_index = 0;
2788
                goto found;
2789
            }
2790

    
2791
            for(stream_index = 0; stream_index < stream->nb_streams;
2792
                stream_index++) {
2793
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2794
                         stream->filename, stream_index);
2795
                if (!strcmp(path, buf))
2796
                    goto found;
2797
            }
2798
        }
2799
    }
2800
    /* no stream found */
2801
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2802
    return;
2803
 found:
2804

    
2805
    /* generate session id if needed */
2806
    if (h->session_id[0] == '\0')
2807
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2808
                 av_random(&random_state), av_random(&random_state));
2809

    
2810
    /* find rtp session, and create it if none found */
2811
    rtp_c = find_rtp_session(h->session_id);
2812
    if (!rtp_c) {
2813
        /* always prefer UDP */
2814
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2815
        if (!th) {
2816
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2817
            if (!th) {
2818
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2819
                return;
2820
            }
2821
        }
2822

    
2823
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2824
                                   th->protocol);
2825
        if (!rtp_c) {
2826
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2827
            return;
2828
        }
2829

    
2830
        /* open input stream */
2831
        if (open_input_stream(rtp_c, "") < 0) {
2832
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2833
            return;
2834
        }
2835
    }
2836

    
2837
    /* test if stream is OK (test needed because several SETUP needs
2838
       to be done for a given file) */
2839
    if (rtp_c->stream != stream) {
2840
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2841
        return;
2842
    }
2843

    
2844
    /* test if stream is already set up */
2845
    if (rtp_c->rtp_ctx[stream_index]) {
2846
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2847
        return;
2848
    }
2849

    
2850
    /* check transport */
2851
    th = find_transport(h, rtp_c->rtp_protocol);
2852
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2853
                th->client_port_min <= 0)) {
2854
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2855
        return;
2856
    }
2857

    
2858
    /* setup default options */
2859
    setup.transport_option[0] = '\0';
2860
    dest_addr = rtp_c->from_addr;
2861
    dest_addr.sin_port = htons(th->client_port_min);
2862

    
2863
    /* setup stream */
2864
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2865
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2866
        return;
2867
    }
2868

    
2869
    /* now everything is OK, so we can send the connection parameters */
2870
    rtsp_reply_header(c, RTSP_STATUS_OK);
2871
    /* session ID */
2872
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2873

    
2874
    switch(rtp_c->rtp_protocol) {
2875
    case RTSP_PROTOCOL_RTP_UDP:
2876
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2877
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2878
                    "client_port=%d-%d;server_port=%d-%d",
2879
                    th->client_port_min, th->client_port_min + 1,
2880
                    port, port + 1);
2881
        break;
2882
    case RTSP_PROTOCOL_RTP_TCP:
2883
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2884
                    stream_index * 2, stream_index * 2 + 1);
2885
        break;
2886
    default:
2887
        break;
2888
    }
2889
    if (setup.transport_option[0] != '\0')
2890
        url_fprintf(c->pb, ";%s", setup.transport_option);
2891
    url_fprintf(c->pb, "\r\n");
2892

    
2893

    
2894
    url_fprintf(c->pb, "\r\n");
2895
}
2896

    
2897

    
2898
/* find an rtp connection by using the session ID. Check consistency
2899
   with filename */
2900
static HTTPContext *find_rtp_session_with_url(const char *url,
2901
                                              const char *session_id)
2902
{
2903
    HTTPContext *rtp_c;
2904
    char path1[1024];
2905
    const char *path;
2906
    char buf[1024];
2907
    int s;
2908

    
2909
    rtp_c = find_rtp_session(session_id);
2910
    if (!rtp_c)
2911
        return NULL;
2912

    
2913
    /* find which url is asked */
2914
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2915
    path = path1;
2916
    if (*path == '/')
2917
        path++;
2918
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2919
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2920
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2921
        rtp_c->stream->filename, s);
2922
      if(!strncmp(path, buf, sizeof(buf))) {
2923
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2924
        return rtp_c;
2925
      }
2926
    }
2927
    return NULL;
2928
}
2929

    
2930
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2931
{
2932
    HTTPContext *rtp_c;
2933

    
2934
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2935
    if (!rtp_c) {
2936
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2937
        return;
2938
    }
2939

    
2940
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2941
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2942
        rtp_c->state != HTTPSTATE_READY) {
2943
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2944
        return;
2945
    }
2946

    
2947
#if 0
2948
    /* XXX: seek in stream */
2949
    if (h->range_start != AV_NOPTS_VALUE) {
2950
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2951
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2952
    }
2953
#endif
2954

    
2955
    rtp_c->state = HTTPSTATE_SEND_DATA;
2956

    
2957
    /* now everything is OK, so we can send the connection parameters */
2958
    rtsp_reply_header(c, RTSP_STATUS_OK);
2959
    /* session ID */
2960
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2961
    url_fprintf(c->pb, "\r\n");
2962
}
2963

    
2964
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2965
{
2966
    HTTPContext *rtp_c;
2967

    
2968
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2969
    if (!rtp_c) {
2970
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2971
        return;
2972
    }
2973

    
2974
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2975
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2976
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2977
        return;
2978
    }
2979

    
2980
    rtp_c->state = HTTPSTATE_READY;
2981
    rtp_c->first_pts = AV_NOPTS_VALUE;
2982
    /* now everything is OK, so we can send the connection parameters */
2983
    rtsp_reply_header(c, RTSP_STATUS_OK);
2984
    /* session ID */
2985
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2986
    url_fprintf(c->pb, "\r\n");
2987
}
2988

    
2989
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2990
{
2991
    HTTPContext *rtp_c;
2992
    char session_id[32];
2993

    
2994
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2995
    if (!rtp_c) {
2996
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2997
        return;
2998
    }
2999

    
3000
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3001

    
3002
    /* abort the session */
3003
    close_connection(rtp_c);
3004

    
3005
    /* now everything is OK, so we can send the connection parameters */
3006
    rtsp_reply_header(c, RTSP_STATUS_OK);
3007
    /* session ID */
3008
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3009
    url_fprintf(c->pb, "\r\n");
3010
}
3011

    
3012

    
3013
/********************************************************************/
3014
/* RTP handling */
3015

    
3016
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3017
                                       FFStream *stream, const char *session_id,
3018
                                       enum RTSPProtocol rtp_protocol)
3019
{
3020
    HTTPContext *c = NULL;
3021
    const char *proto_str;
3022

    
3023
    /* XXX: should output a warning page when coming
3024
       close to the connection limit */
3025
    if (nb_connections >= nb_max_connections)
3026
        goto fail;
3027

    
3028
    /* add a new connection */
3029
    c = av_mallocz(sizeof(HTTPContext));
3030
    if (!c)
3031
        goto fail;
3032

    
3033
    c->fd = -1;
3034
    c->poll_entry = NULL;
3035
    c->from_addr = *from_addr;
3036
    c->buffer_size = IOBUFFER_INIT_SIZE;
3037
    c->buffer = av_malloc(c->buffer_size);
3038
    if (!c->buffer)
3039
        goto fail;
3040
    nb_connections++;
3041
    c->stream = stream;
3042
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3043
    c->state = HTTPSTATE_READY;
3044
    c->is_packetized = 1;
3045
    c->rtp_protocol = rtp_protocol;
3046

    
3047
    /* protocol is shown in statistics */
3048
    switch(c->rtp_protocol) {
3049
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3050
        proto_str = "MCAST";
3051
        break;
3052
    case RTSP_PROTOCOL_RTP_UDP:
3053
        proto_str = "UDP";
3054
        break;
3055
    case RTSP_PROTOCOL_RTP_TCP:
3056
        proto_str = "TCP";
3057
        break;
3058
    default:
3059
        proto_str = "???";
3060
        break;
3061
    }
3062
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3063
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3064

    
3065
    current_bandwidth += stream->bandwidth;
3066

    
3067
    c->next = first_http_ctx;
3068
    first_http_ctx = c;
3069
    return c;
3070

    
3071
 fail:
3072
    if (c) {
3073
        av_free(c->buffer);
3074
        av_free(c);
3075
    }
3076
    return NULL;
3077
}
3078

    
3079
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3080
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3081
   used. */
3082
static int rtp_new_av_stream(HTTPContext *c,
3083
                             int stream_index, struct sockaddr_in *dest_addr,
3084
                             HTTPContext *rtsp_c)
3085
{
3086
    AVFormatContext *ctx;
3087
    AVStream *st;
3088
    char *ipaddr;
3089
    URLContext *h = NULL;
3090
    uint8_t *dummy_buf;
3091
    char buf2[32];
3092
    int max_packet_size;
3093

    
3094
    /* now we can open the relevant output stream */
3095
    ctx = av_alloc_format_context();
3096
    if (!ctx)
3097
        return -1;
3098
    ctx->oformat = guess_format("rtp", NULL, NULL);
3099

    
3100
    st = av_mallocz(sizeof(AVStream));
3101
    if (!st)
3102
        goto fail;
3103
    st->codec= avcodec_alloc_context();
3104
    ctx->nb_streams = 1;
3105
    ctx->streams[0] = st;
3106

    
3107
    if (!c->stream->feed ||
3108
        c->stream->feed == c->stream)
3109
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3110
    else
3111
        memcpy(st,
3112
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3113
               sizeof(AVStream));
3114
    st->priv_data = NULL;
3115

    
3116
    /* build destination RTP address */
3117
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3118

    
3119
    switch(c->rtp_protocol) {
3120
    case RTSP_PROTOCOL_RTP_UDP:
3121
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3122
        /* RTP/UDP case */
3123

    
3124
        /* XXX: also pass as parameter to function ? */
3125
        if (c->stream->is_multicast) {
3126
            int ttl;
3127
            ttl = c->stream->multicast_ttl;
3128
            if (!ttl)
3129
                ttl = 16;
3130
            snprintf(ctx->filename, sizeof(ctx->filename),
3131
                     "rtp://%s:%d?multicast=1&ttl=%d",
3132
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3133
        } else {
3134
            snprintf(ctx->filename, sizeof(ctx->filename),
3135
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3136
        }
3137

    
3138
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3139
            goto fail;
3140
        c->rtp_handles[stream_index] = h;
3141
        max_packet_size = url_get_max_packet_size(h);
3142
        break;
3143
    case RTSP_PROTOCOL_RTP_TCP:
3144
        /* RTP/TCP case */
3145
        c->rtsp_c = rtsp_c;
3146
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3147
        break;
3148
    default:
3149
        goto fail;
3150
    }
3151

    
3152
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3153
             ipaddr, ntohs(dest_addr->sin_port),
3154
             ctime1(buf2),
3155
             c->stream->filename, stream_index, c->protocol);
3156

    
3157
    /* normally, no packets should be output here, but the packet size may be checked */
3158
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3159
        /* XXX: close stream */
3160
        goto fail;
3161
    }
3162
    av_set_parameters(ctx, NULL);
3163
    if (av_write_header(ctx) < 0) {
3164
    fail:
3165
        if (h)
3166
            url_close(h);
3167
        av_free(ctx);
3168
        return -1;
3169
    }
3170
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3171
    av_free(dummy_buf);
3172

    
3173
    c->rtp_ctx[stream_index] = ctx;
3174
    return 0;
3175
}
3176

    
3177
/********************************************************************/
3178
/* ffserver initialization */
3179

    
3180
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3181
{
3182
    AVStream *fst;
3183

    
3184
    fst = av_mallocz(sizeof(AVStream));
3185
    if (!fst)
3186
        return NULL;
3187
    fst->codec= avcodec_alloc_context();
3188
    fst->priv_data = av_mallocz(sizeof(FeedData));
3189
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3190
    fst->index = stream->nb_streams;
3191
    av_set_pts_info(fst, 33, 1, 90000);
3192
    stream->streams[stream->nb_streams++] = fst;
3193
    return fst;
3194
}
3195

    
3196
/* return the stream number in the feed */
3197
static int add_av_stream(FFStream *feed, AVStream *st)
3198
{
3199
    AVStream *fst;
3200
    AVCodecContext *av, *av1;
3201
    int i;
3202

    
3203
    av = st->codec;
3204
    for(i=0;i<feed->nb_streams;i++) {
3205
        st = feed->streams[i];
3206
        av1 = st->codec;
3207
        if (av1->codec_id == av->codec_id &&
3208
            av1->codec_type == av->codec_type &&
3209
            av1->bit_rate == av->bit_rate) {
3210

    
3211
            switch(av->codec_type) {
3212
            case CODEC_TYPE_AUDIO:
3213
                if (av1->channels == av->channels &&
3214
                    av1->sample_rate == av->sample_rate)
3215
                    goto found;
3216
                break;
3217
            case CODEC_TYPE_VIDEO:
3218
                if (av1->width == av->width &&
3219
                    av1->height == av->height &&
3220
                    av1->time_base.den == av->time_base.den &&
3221
                    av1->time_base.num == av->time_base.num &&
3222
                    av1->gop_size == av->gop_size)
3223
                    goto found;
3224
                break;
3225
            default:
3226
                abort();
3227
            }
3228
        }
3229
    }
3230

    
3231
    fst = add_av_stream1(feed, av);
3232
    if (!fst)
3233
        return -1;
3234
    return feed->nb_streams - 1;
3235
 found:
3236
    return i;
3237
}
3238

    
3239
static void remove_stream(FFStream *stream)
3240
{
3241
    FFStream **ps;
3242
    ps = &first_stream;
3243
    while (*ps != NULL) {
3244
        if (*ps == stream)
3245
            *ps = (*ps)->next;
3246
        else
3247
            ps = &(*ps)->next;
3248
    }
3249
}
3250

    
3251
/* specific mpeg4 handling : we extract the raw parameters */
3252
static void extract_mpeg4_header(AVFormatContext *infile)
3253
{
3254
    int mpeg4_count, i, size;
3255
    AVPacket pkt;
3256
    AVStream *st;
3257
    const uint8_t *p;
3258

    
3259
    mpeg4_count = 0;
3260
    for(i=0;i<infile->nb_streams;i++) {
3261
        st = infile->streams[i];
3262
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3263
            st->codec->extradata_size == 0) {
3264
            mpeg4_count++;
3265
        }
3266
    }
3267
    if (!mpeg4_count)
3268
        return;
3269

    
3270
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3271
    while (mpeg4_count > 0) {
3272
        if (av_read_packet(infile, &pkt) < 0)
3273
            break;
3274
        st = infile->streams[pkt.stream_index];
3275
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3276
            st->codec->extradata_size == 0) {
3277
            av_freep(&st->codec->extradata);
3278
            /* fill extradata with the header */
3279
            /* XXX: we make hard suppositions here ! */
3280
            p = pkt.data;
3281
            while (p < pkt.data + pkt.size - 4) {
3282
                /* stop when vop header is found */
3283
                if (p[0] == 0x00 && p[1] == 0x00 &&
3284
                    p[2] == 0x01 && p[3] == 0xb6) {
3285
                    size = p - pkt.data;
3286
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3287
                    st->codec->extradata = av_malloc(size);
3288
                    st->codec->extradata_size = size;
3289
                    memcpy(st->codec->extradata, pkt.data, size);
3290
                    break;
3291
                }
3292
                p++;
3293
            }
3294
            mpeg4_count--;
3295
        }
3296
        av_free_packet(&pkt);
3297
    }
3298
}
3299

    
3300
/* compute the needed AVStream for each file */
3301
static void build_file_streams(void)
3302
{
3303
    FFStream *stream, *stream_next;
3304
    AVFormatContext *infile;
3305
    int i, ret;
3306

    
3307
    /* gather all streams */
3308
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3309
        stream_next = stream->next;
3310
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3311
            !stream->feed) {
3312
            /* the stream comes from a file */
3313
            /* try to open the file */
3314
            /* open stream */
3315
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3316
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3317
                /* specific case : if transport stream output to RTP,
3318
                   we use a raw transport stream reader */
3319
                stream->ap_in->mpeg2ts_raw = 1;
3320
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3321
            }
3322

    
3323
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3324
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3325
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3326
                /* remove stream (no need to spend more time on it) */
3327
            fail:
3328
                remove_stream(stream);
3329
            } else {
3330
                /* find all the AVStreams inside and reference them in
3331
                   'stream' */
3332
                if (av_find_stream_info(infile) < 0) {
3333
                    http_log("Could not find codec parameters from '%s'",
3334
                             stream->feed_filename);
3335
                    av_close_input_file(infile);
3336
                    goto fail;
3337
                }
3338
                extract_mpeg4_header(infile);
3339

    
3340
                for(i=0;i<infile->nb_streams;i++)
3341
                    add_av_stream1(stream, infile->streams[i]->codec);
3342

    
3343
                av_close_input_file(infile);
3344
            }
3345
        }
3346
    }
3347
}
3348

    
3349
/* compute the needed AVStream for each feed */
3350
static void build_feed_streams(void)
3351
{
3352
    FFStream *stream, *feed;
3353
    int i;
3354

    
3355
    /* gather all streams */
3356
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3357
        feed = stream->feed;
3358
        if (feed) {
3359
            if (!stream->is_feed) {
3360
                /* we handle a stream coming from a feed */
3361
                for(i=0;i<stream->nb_streams;i++)
3362
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3363
            }
3364
        }
3365
    }
3366

    
3367
    /* gather all streams */
3368
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3369
        feed = stream->feed;
3370
        if (feed) {
3371
            if (stream->is_feed) {
3372
                for(i=0;i<stream->nb_streams;i++)
3373
                    stream->feed_streams[i] = i;
3374
            }
3375
        }
3376
    }
3377

    
3378
    /* create feed files if needed */
3379
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3380
        int fd;
3381

    
3382
        if (url_exist(feed->feed_filename)) {
3383
            /* See if it matches */
3384
            AVFormatContext *s;
3385
            int matches = 0;
3386

    
3387
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3388
                /* Now see if it matches */
3389
                if (s->nb_streams == feed->nb_streams) {
3390
                    matches = 1;
3391
                    for(i=0;i<s->nb_streams;i++) {
3392
                        AVStream *sf, *ss;
3393
                        sf = feed->streams[i];
3394
                        ss = s->streams[i];
3395

    
3396
                        if (sf->index != ss->index ||
3397
                            sf->id != ss->id) {
3398
                            printf("Index & Id do not match for stream %d (%s)\n",
3399
                                   i, feed->feed_filename);
3400
                            matches = 0;
3401
                        } else {
3402
                            AVCodecContext *ccf, *ccs;
3403

    
3404
                            ccf = sf->codec;
3405
                            ccs = ss->codec;
3406
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3407

    
3408
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3409
                                printf("Codecs do not match for stream %d\n", i);
3410
                                matches = 0;
3411
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3412
                                printf("Codec bitrates do not match for stream %d\n", i);
3413
                                matches = 0;
3414
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3415
                                if (CHECK_CODEC(time_base.den) ||
3416
                                    CHECK_CODEC(time_base.num) ||
3417
                                    CHECK_CODEC(width) ||
3418
                                    CHECK_CODEC(height)) {
3419
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3420
                                    matches = 0;
3421
                                }
3422
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3423
                                if (CHECK_CODEC(sample_rate) ||
3424
                                    CHECK_CODEC(channels) ||
3425
                                    CHECK_CODEC(frame_size)) {
3426
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3427
                                    matches = 0;
3428
                                }
3429
                            } else {
3430
                                printf("Unknown codec type\n");
3431
                                matches = 0;
3432
                            }
3433
                        }
3434
                        if (!matches)
3435
                            break;
3436
                    }
3437
                } else
3438
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3439
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3440

    
3441
                av_close_input_file(s);
3442
            } else
3443
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3444
                        feed->feed_filename);
3445

    
3446
            if (!matches) {
3447
                if (feed->readonly) {
3448
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3449
                        feed->feed_filename);
3450
                    exit(1);
3451
                }
3452
                unlink(feed->feed_filename);
3453
            }
3454
        }
3455
        if (!url_exist(feed->feed_filename)) {
3456
            AVFormatContext s1, *s = &s1;
3457

    
3458
            if (feed->readonly) {
3459
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3460
                    feed->feed_filename);
3461
                exit(1);
3462
            }
3463

    
3464
            /* only write the header of the ffm file */
3465
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3466
                fprintf(stderr, "Could not open output feed file '%s'\n",
3467
                        feed->feed_filename);
3468
                exit(1);
3469
            }
3470
            s->oformat = feed->fmt;
3471
            s->nb_streams = feed->nb_streams;
3472
            for(i=0;i<s->nb_streams;i++) {
3473
                AVStream *st;
3474
                st = feed->streams[i];
3475
                s->streams[i] = st;
3476
            }
3477
            av_set_parameters(s, NULL);
3478
            if (av_write_header(s) < 0) {
3479
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3480
                exit(1);
3481
            }
3482
            /* XXX: need better api */
3483
            av_freep(&s->priv_data);
3484
            url_fclose(s->pb);
3485
        }
3486
        /* get feed size and write index */
3487
        fd = open(feed->feed_filename, O_RDONLY);
3488
        if (fd < 0) {
3489
            fprintf(stderr, "Could not open output feed file '%s'\n",
3490
                    feed->feed_filename);
3491
            exit(1);
3492
        }
3493

    
3494
        feed->feed_write_index = ffm_read_write_index(fd);
3495
        feed->feed_size = lseek(fd, 0, SEEK_END);
3496
        /* ensure that we do not wrap before the end of file */
3497
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3498
            feed->feed_max_size = feed->feed_size;
3499

    
3500
        close(fd);
3501
    }
3502
}
3503

    
3504
/* compute the bandwidth used by each stream */
3505
static void compute_bandwidth(void)
3506
{
3507
    int bandwidth, i;
3508
    FFStream *stream;
3509

    
3510
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3511
        bandwidth = 0;
3512
        for(i=0;i<stream->nb_streams;i++) {
3513
            AVStream *st = stream->streams[i];
3514
            switch(st->codec->codec_type) {
3515
            case CODEC_TYPE_AUDIO:
3516
            case CODEC_TYPE_VIDEO:
3517
                bandwidth += st->codec->bit_rate;
3518
                break;
3519
            default:
3520
                break;
3521
            }
3522
        }
3523
        stream->bandwidth = (bandwidth + 999) / 1000;
3524
    }
3525
}
3526

    
3527
static void get_arg(char *buf, int buf_size, const char **pp)
3528
{
3529
    const char *p;
3530
    char *q;
3531
    int quote;
3532

    
3533
    p = *pp;
3534
    while (isspace(*p)) p++;
3535
    q = buf;
3536
    quote = 0;
3537
    if (*p == '\"' || *p == '\'')
3538
        quote = *p++;
3539
    for(;;) {
3540
        if (quote) {
3541
            if (*p == quote)
3542
                break;
3543
        } else {
3544
            if (isspace(*p))
3545
                break;
3546
        }
3547
        if (*p == '\0')
3548
            break;
3549
        if ((q - buf) < buf_size - 1)
3550
            *q++ = *p;
3551
        p++;
3552
    }
3553
    *q = '\0';
3554
    if (quote && *p == quote)
3555
        p++;
3556
    *pp = p;
3557
}
3558

    
3559
/* add a codec and set the default parameters */
3560
static void add_codec(FFStream *stream, AVCodecContext *av)
3561
{
3562
    AVStream *st;
3563

    
3564
    /* compute default parameters */
3565
    switch(av->codec_type) {
3566
    case CODEC_TYPE_AUDIO:
3567
        if (av->bit_rate == 0)
3568
            av->bit_rate = 64000;
3569
        if (av->sample_rate == 0)
3570
            av->sample_rate = 22050;
3571
        if (av->channels == 0)
3572
            av->channels = 1;
3573
        break;
3574
    case CODEC_TYPE_VIDEO:
3575
        if (av->bit_rate == 0)
3576
            av->bit_rate = 64000;
3577
        if (av->time_base.num == 0){
3578
            av->time_base.den = 5;
3579
            av->time_base.num = 1;
3580
        }
3581
        if (av->width == 0 || av->height == 0) {
3582
            av->width = 160;
3583
            av->height = 128;
3584
        }
3585
        /* Bitrate tolerance is less for streaming */
3586
        if (av->bit_rate_tolerance == 0)
3587
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3588
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3589
        if (av->qmin == 0)
3590
            av->qmin = 3;
3591
        if (av->qmax == 0)
3592
            av->qmax = 31;
3593
        if (av->max_qdiff == 0)
3594
            av->max_qdiff = 3;
3595
        av->qcompress = 0.5;
3596
        av->qblur = 0.5;
3597

    
3598
        if (!av->nsse_weight)
3599
            av->nsse_weight = 8;
3600

    
3601
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3602
        av->me_method = ME_EPZS;
3603
        av->rc_buffer_aggressivity = 1.0;
3604

    
3605
        if (!av->rc_eq)
3606
            av->rc_eq = "tex^qComp";
3607
        if (!av->i_quant_factor)
3608
            av->i_quant_factor = -0.8;
3609
        if (!av->b_quant_factor)
3610
            av->b_quant_factor = 1.25;
3611
        if (!av->b_quant_offset)
3612
            av->b_quant_offset = 1.25;
3613
        if (!av->rc_max_rate)
3614
            av->rc_max_rate = av->bit_rate * 2;
3615

    
3616
        if (av->rc_max_rate && !av->rc_buffer_size) {
3617
            av->rc_buffer_size = av->rc_max_rate;
3618
        }
3619

    
3620

    
3621
        break;
3622
    default:
3623
        abort();
3624
    }
3625

    
3626
    st = av_mallocz(sizeof(AVStream));
3627
    if (!st)
3628
        return;
3629
    st->codec = avcodec_alloc_context();
3630
    stream->streams[stream->nb_streams++] = st;
3631
    memcpy(st->codec, av, sizeof(AVCodecContext));
3632
}
3633

    
3634
static int opt_audio_codec(const char *arg)
3635
{
3636
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3637

    
3638
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3639
        return CODEC_ID_NONE;
3640

    
3641
    return p->id;
3642
}
3643

    
3644
static int opt_video_codec(const char *arg)
3645
{
3646
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3647

    
3648
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3649
        return CODEC_ID_NONE;
3650

    
3651
    return p->id;
3652
}
3653

    
3654
/* simplistic plugin support */
3655

    
3656
#ifdef HAVE_DLOPEN
3657
static void load_module(const char *filename)
3658
{
3659
    void *dll;
3660
    void (*init_func)(void);
3661
    dll = dlopen(filename, RTLD_NOW);
3662
    if (!dll) {
3663
        fprintf(stderr, "Could not load module '%s' - %s\n",
3664
                filename, dlerror());
3665
        return;
3666
    }
3667

    
3668
    init_func = dlsym(dll, "ffserver_module_init");
3669
    if (!init_func) {
3670
        fprintf(stderr,
3671
                "%s: init function 'ffserver_module_init()' not found\n",
3672
                filename);
3673
        dlclose(dll);
3674
    }
3675

    
3676
    init_func();
3677
}
3678
#endif
3679

    
3680
static int parse_ffconfig(const char *filename)
3681
{
3682
    FILE *f;
3683
    char line[1024];
3684
    char cmd[64];
3685
    char arg[1024];
3686
    const char *p;
3687
    int val, errors, line_num;
3688
    FFStream **last_stream, *stream, *redirect;
3689
    FFStream **last_feed, *feed;
3690
    AVCodecContext audio_enc, video_enc;
3691
    int audio_id, video_id;
3692

    
3693
    f = fopen(filename, "r");
3694
    if (!f) {
3695
        perror(filename);
3696
        return -1;
3697
    }
3698

    
3699
    errors = 0;
3700
    line_num = 0;
3701
    first_stream = NULL;
3702
    last_stream = &first_stream;
3703
    first_feed = NULL;
3704
    last_feed = &first_feed;
3705
    stream = NULL;
3706
    feed = NULL;
3707
    redirect = NULL;
3708
    audio_id = CODEC_ID_NONE;
3709
    video_id = CODEC_ID_NONE;
3710
    for(;;) {
3711
        if (fgets(line, sizeof(line), f) == NULL)
3712
            break;
3713
        line_num++;
3714
        p = line;
3715
        while (isspace(*p))
3716
            p++;
3717
        if (*p == '\0' || *p == '#')
3718
            continue;
3719

    
3720
        get_arg(cmd, sizeof(cmd), &p);
3721

    
3722
        if (!strcasecmp(cmd, "Port")) {
3723
            get_arg(arg, sizeof(arg), &p);
3724
            val = atoi(arg);
3725
            if (val < 1 || val > 65536) {
3726
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3727
                        filename, line_num, arg);
3728
                errors++;
3729
            }
3730
            my_http_addr.sin_port = htons(val);
3731
        } else if (!strcasecmp(cmd, "BindAddress")) {
3732
            get_arg(arg, sizeof(arg), &p);
3733
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3734
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3735
                        filename, line_num, arg);
3736
                errors++;
3737
            }
3738
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3739
            ffserver_daemon = 0;
3740
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3741
            get_arg(arg, sizeof(arg), &p);
3742
            val = atoi(arg);
3743
            if (val < 1 || val > 65536) {
3744
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3745
                        filename, line_num, arg);
3746
                errors++;
3747
            }
3748
            my_rtsp_addr.sin_port = htons(atoi(arg));
3749
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3750
            get_arg(arg, sizeof(arg), &p);
3751
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3752
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3753
                        filename, line_num, arg);
3754
                errors++;
3755
            }
3756
        } else if (!strcasecmp(cmd, "MaxClients")) {
3757
            get_arg(arg, sizeof(arg), &p);
3758
            val = atoi(arg);
3759
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3760
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3761
                        filename, line_num, arg);
3762
                errors++;
3763
            } else {
3764
                nb_max_connections = val;
3765
            }
3766
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3767
            get_arg(arg, sizeof(arg), &p);
3768
            val = atoi(arg);
3769
            if (val < 10 || val > 100000) {
3770
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3771
                        filename, line_num, arg);
3772
                errors++;
3773
            } else
3774
                max_bandwidth = val;
3775
        } else if (!strcasecmp(cmd, "CustomLog")) {
3776
            get_arg(logfilename, sizeof(logfilename), &p);
3777
        } else if (!strcasecmp(cmd, "<Feed")) {
3778
            /*********************************************/
3779
            /* Feed related options */
3780
            char *q;
3781
            if (stream || feed) {
3782
                fprintf(stderr, "%s:%d: Already in a tag\n",
3783
                        filename, line_num);
3784
            } else {
3785
                feed = av_mallocz(sizeof(FFStream));
3786
                /* add in stream list */
3787
                *last_stream = feed;
3788
                last_stream = &feed->next;
3789
                /* add in feed list */
3790
                *last_feed = feed;
3791
                last_feed = &feed->next_feed;
3792

    
3793
                get_arg(feed->filename, sizeof(feed->filename), &p);
3794
                q = strrchr(feed->filename, '>');
3795
                if (*q)
3796
                    *q = '\0';
3797
                feed->fmt = guess_format("ffm", NULL, NULL);
3798
                /* defaut feed file */
3799
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3800
                         "/tmp/%s.ffm", feed->filename);
3801
                feed->feed_max_size = 5 * 1024 * 1024;
3802
                feed->is_feed = 1;
3803
                feed->feed = feed; /* self feeding :-) */
3804
            }
3805
        } else if (!strcasecmp(cmd, "Launch")) {
3806
            if (feed) {
3807
                int i;
3808

    
3809
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3810

    
3811
                for (i = 0; i < 62; i++) {
3812
                    get_arg(arg, sizeof(arg), &p);
3813
                    if (!arg[0])
3814
                        break;
3815

    
3816
                    feed->child_argv[i] = av_strdup(arg);
3817
                }
3818

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

    
3821
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3822
                    "http://%s:%d/%s",
3823
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3824
                    inet_ntoa(my_http_addr.sin_addr),
3825
                    ntohs(my_http_addr.sin_port), feed->filename);
3826

    
3827
                if (ffserver_debug)
3828
                {
3829
                    int j;
3830
                    fprintf(stdout, "Launch commandline: ");
3831
                    for (j = 0; j <= i; j++)
3832
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3833
                    fprintf(stdout, "\n");
3834
                }
3835
            }
3836
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3837
            if (feed) {
3838
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3839
                feed->readonly = 1;
3840
            } else if (stream) {
3841
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3842
            }
3843
        } else if (!strcasecmp(cmd, "File")) {
3844
            if (feed) {
3845
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3846
            } else if (stream)
3847
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3848
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3849
            if (feed) {
3850
                char *p1;
3851
                double fsize;
3852

    
3853
                get_arg(arg, sizeof(arg), &p);
3854
                p1 = arg;
3855
                fsize = strtod(p1, &p1);
3856
                switch(toupper(*p1)) {
3857
                case 'K':
3858
                    fsize *= 1024;
3859
                    break;
3860
                case 'M':
3861
                    fsize *= 1024 * 1024;
3862
                    break;
3863
                case 'G':
3864
                    fsize *= 1024 * 1024 * 1024;
3865
                    break;
3866
                }
3867
                feed->feed_max_size = (int64_t)fsize;
3868
            }
3869
        } else if (!strcasecmp(cmd, "</Feed>")) {
3870
            if (!feed) {
3871
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3872
                        filename, line_num);
3873
                errors++;
3874
            }
3875
            feed = NULL;
3876
        } else if (!strcasecmp(cmd, "<Stream")) {
3877
            /*********************************************/
3878
            /* Stream related options */
3879
            char *q;
3880
            if (stream || feed) {
3881
                fprintf(stderr, "%s:%d: Already in a tag\n",
3882
                        filename, line_num);
3883
            } else {
3884
                stream = av_mallocz(sizeof(FFStream));
3885
                *last_stream = stream;
3886
                last_stream = &stream->next;
3887

    
3888
                get_arg(stream->filename, sizeof(stream->filename), &p);
3889
                q = strrchr(stream->filename, '>');
3890
                if (*q)
3891
                    *q = '\0';
3892
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3893
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3894
                memset(&video_enc, 0, sizeof(AVCodecContext));
3895
                audio_id = CODEC_ID_NONE;
3896
                video_id = CODEC_ID_NONE;
3897
                if (stream->fmt) {
3898
                    audio_id = stream->fmt->audio_codec;
3899
                    video_id = stream->fmt->video_codec;
3900
                }
3901
            }
3902
        } else if (!strcasecmp(cmd, "Feed")) {
3903
            get_arg(arg, sizeof(arg), &p);
3904
            if (stream) {
3905
                FFStream *sfeed;
3906

    
3907
                sfeed = first_feed;
3908
                while (sfeed != NULL) {
3909
                    if (!strcmp(sfeed->filename, arg))
3910
                        break;
3911
                    sfeed = sfeed->next_feed;
3912
                }
3913
                if (!sfeed)
3914
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3915
                            filename, line_num, arg);
3916
                else
3917
                    stream->feed = sfeed;
3918
            }
3919
        } else if (!strcasecmp(cmd, "Format")) {
3920
            get_arg(arg, sizeof(arg), &p);
3921
            if (stream) {
3922
            if (!strcmp(arg, "status")) {
3923
                stream->stream_type = STREAM_TYPE_STATUS;
3924
                stream->fmt = NULL;
3925
            } else {
3926
                stream->stream_type = STREAM_TYPE_LIVE;
3927
                /* jpeg cannot be used here, so use single frame jpeg */
3928
                if (!strcmp(arg, "jpeg"))
3929
                    strcpy(arg, "mjpeg");
3930
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3931
                if (!stream->fmt) {
3932
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
3933
                            filename, line_num, arg);
3934
                    errors++;
3935
                }
3936
            }
3937
            if (stream->fmt) {
3938
                audio_id = stream->fmt->audio_codec;
3939
                video_id = stream->fmt->video_codec;
3940
            }
3941
            }
3942
        } else if (!strcasecmp(cmd, "InputFormat")) {
3943
            get_arg(arg, sizeof(arg), &p);
3944
            stream->ifmt = av_find_input_format(arg);
3945
            if (!stream->ifmt) {
3946
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
3947
                        filename, line_num, arg);
3948
            }
3949
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3950
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3951
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3952
            } else {
3953
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
3954
                            filename, line_num);
3955
                errors++;
3956
            }
3957
        } else if (!strcasecmp(cmd, "Author")) {
3958
            if (stream)
3959
                get_arg(stream->author, sizeof(stream->author), &p);
3960
        } else if (!strcasecmp(cmd, "Comment")) {
3961
            if (stream)
3962
                get_arg(stream->comment, sizeof(stream->comment), &p);
3963
        } else if (!strcasecmp(cmd, "Copyright")) {
3964
            if (stream)
3965
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
3966
        } else if (!strcasecmp(cmd, "Title")) {
3967
            if (stream)
3968
                get_arg(stream->title, sizeof(stream->title), &p);
3969
        } else if (!strcasecmp(cmd, "Preroll")) {
3970
            get_arg(arg, sizeof(arg), &p);
3971
            if (stream)
3972
                stream->prebuffer = atof(arg) * 1000;
3973
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3974
            if (stream)
3975
                stream->send_on_key = 1;
3976
        } else if (!strcasecmp(cmd, "AudioCodec")) {
3977
            get_arg(arg, sizeof(arg), &p);
3978
            audio_id = opt_audio_codec(arg);
3979
            if (audio_id == CODEC_ID_NONE) {
3980
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
3981
                        filename, line_num, arg);
3982
                errors++;
3983
            }
3984
        } else if (!strcasecmp(cmd, "VideoCodec")) {
3985
            get_arg(arg, sizeof(arg), &p);
3986
            video_id = opt_video_codec(arg);
3987
            if (video_id == CODEC_ID_NONE) {
3988
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
3989
                        filename, line_num, arg);
3990
                errors++;
3991
            }
3992
        } else if (!strcasecmp(cmd, "MaxTime")) {
3993
            get_arg(arg, sizeof(arg), &p);
3994
            if (stream)
3995
                stream->max_time = atof(arg) * 1000;
3996
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
3997
            get_arg(arg, sizeof(arg), &p);
3998
            if (stream)
3999
                audio_enc.bit_rate = atoi(arg) * 1000;
4000
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4001
            get_arg(arg, sizeof(arg), &p);
4002
            if (stream)
4003
                audio_enc.channels = atoi(arg);
4004
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4005
            get_arg(arg, sizeof(arg), &p);
4006
            if (stream)
4007
                audio_enc.sample_rate = atoi(arg);
4008
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4009
            get_arg(arg, sizeof(arg), &p);
4010
            if (stream) {
4011
//                audio_enc.quality = atof(arg) * 1000;
4012
            }
4013
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4014
            if (stream) {
4015
                int minrate, maxrate;
4016

    
4017
                get_arg(arg, sizeof(arg), &p);
4018

    
4019
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4020
                    video_enc.rc_min_rate = minrate * 1000;
4021
                    video_enc.rc_max_rate = maxrate * 1000;
4022
                } else {
4023
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4024
                            filename, line_num, arg);
4025
                    errors++;
4026
                }
4027
            }
4028
        } else if (!strcasecmp(cmd, "Debug")) {
4029
            if (stream) {
4030
                get_arg(arg, sizeof(arg), &p);
4031
                video_enc.debug = strtol(arg,0,0);
4032
            }
4033
        } else if (!strcasecmp(cmd, "Strict")) {
4034
            if (stream) {
4035
                get_arg(arg, sizeof(arg), &p);
4036
                video_enc.strict_std_compliance = atoi(arg);
4037
            }
4038
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4039
            if (stream) {
4040
                get_arg(arg, sizeof(arg), &p);
4041
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4042
            }
4043
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4044
            if (stream) {
4045
                get_arg(arg, sizeof(arg), &p);
4046
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4047
            }
4048
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4049
            get_arg(arg, sizeof(arg), &p);
4050
            if (stream) {
4051
                video_enc.bit_rate = atoi(arg) * 1000;
4052
            }
4053
        } else if (!strcasecmp(cmd, "VideoSize")) {
4054
            get_arg(arg, sizeof(arg), &p);
4055
            if (stream) {
4056
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4057
                if ((video_enc.width % 16) != 0 ||
4058
                    (video_enc.height % 16) != 0) {
4059
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4060
                            filename, line_num);
4061
                    errors++;
4062
                }
4063
            }
4064
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4065
            get_arg(arg, sizeof(arg), &p);
4066
            if (stream) {
4067
                AVRational frame_rate;
4068
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4069
                    fprintf(stderr, "Incorrect frame rate\n");
4070
                    errors++;
4071
                } else {
4072
                    video_enc.time_base.num = frame_rate.den;
4073
                    video_enc.time_base.den = frame_rate.num;
4074
                }
4075
            }
4076
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4077
            get_arg(arg, sizeof(arg), &p);
4078
            if (stream)
4079
                video_enc.gop_size = atoi(arg);
4080
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4081
            if (stream)
4082
                video_enc.gop_size = 1;
4083
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4084
            if (stream)
4085
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4086
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4087
            if (stream) {
4088
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4089
                video_enc.flags |= CODEC_FLAG_4MV;
4090
            }
4091
        } else if (!strcasecmp(cmd, "VideoTag")) {
4092
            get_arg(arg, sizeof(arg), &p);
4093
            if ((strlen(arg) == 4) && stream)
4094
                video_enc.codec_tag = ff_get_fourcc(arg);
4095
        } else if (!strcasecmp(cmd, "BitExact")) {
4096
            if (stream)
4097
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4098
        } else if (!strcasecmp(cmd, "DctFastint")) {
4099
            if (stream)
4100
                video_enc.dct_algo  = FF_DCT_FASTINT;
4101
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4102
            if (stream)
4103
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4104
        } else if (!strcasecmp(cmd, "Qscale")) {
4105
            get_arg(arg, sizeof(arg), &p);
4106
            if (stream) {
4107
                video_enc.flags |= CODEC_FLAG_QSCALE;
4108
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4109
            }
4110
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4111
            get_arg(arg, sizeof(arg), &p);
4112
            if (stream) {
4113
                video_enc.max_qdiff = atoi(arg);
4114
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4115
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4116
                            filename, line_num);
4117
                    errors++;
4118
                }
4119
            }
4120
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4121
            get_arg(arg, sizeof(arg), &p);
4122
            if (stream) {
4123
                video_enc.qmax = atoi(arg);
4124
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4125
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4126
                            filename, line_num);
4127
                    errors++;
4128
                }
4129
            }
4130
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4131
            get_arg(arg, sizeof(arg), &p);
4132
            if (stream) {
4133
                video_enc.qmin = atoi(arg);
4134
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4135
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4136
                            filename, line_num);
4137
                    errors++;
4138
                }
4139
            }
4140
        } else if (!strcasecmp(cmd, "LumaElim")) {
4141
            get_arg(arg, sizeof(arg), &p);
4142
            if (stream)
4143
                video_enc.luma_elim_threshold = atoi(arg);
4144
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4145
            get_arg(arg, sizeof(arg), &p);
4146
            if (stream)
4147
                video_enc.chroma_elim_threshold = atoi(arg);
4148
        } else if (!strcasecmp(cmd, "LumiMask")) {
4149
            get_arg(arg, sizeof(arg), &p);
4150
            if (stream)
4151
                video_enc.lumi_masking = atof(arg);
4152
        } else if (!strcasecmp(cmd, "DarkMask")) {
4153
            get_arg(arg, sizeof(arg), &p);
4154
            if (stream)
4155
                video_enc.dark_masking = atof(arg);
4156
        } else if (!strcasecmp(cmd, "NoVideo")) {
4157
            video_id = CODEC_ID_NONE;
4158
        } else if (!strcasecmp(cmd, "NoAudio")) {
4159
            audio_id = CODEC_ID_NONE;
4160
        } else if (!strcasecmp(cmd, "ACL")) {
4161
            IPAddressACL acl;
4162

    
4163
            get_arg(arg, sizeof(arg), &p);
4164
            if (strcasecmp(arg, "allow") == 0)
4165
                acl.action = IP_ALLOW;
4166
            else if (strcasecmp(arg, "deny") == 0)
4167
                acl.action = IP_DENY;
4168
            else {
4169
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4170
                        filename, line_num, arg);
4171
                errors++;
4172
            }
4173

    
4174
            get_arg(arg, sizeof(arg), &p);
4175

    
4176
            if (resolve_host(&acl.first, arg) != 0) {
4177
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4178
                        filename, line_num, arg);
4179
                errors++;
4180
            } else
4181
                acl.last = acl.first;
4182

    
4183
            get_arg(arg, sizeof(arg), &p);
4184

    
4185
            if (arg[0]) {
4186
                if (resolve_host(&acl.last, arg) != 0) {
4187
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4188
                            filename, line_num, arg);
4189
                    errors++;
4190
                }
4191
            }
4192

    
4193
            if (!errors) {
4194
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4195
                IPAddressACL **naclp = 0;
4196

    
4197
                acl.next = 0;
4198
                *nacl = acl;
4199

    
4200
                if (stream)
4201
                    naclp = &stream->acl;
4202
                else if (feed)
4203
                    naclp = &feed->acl;
4204
                else {
4205
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4206
                            filename, line_num);
4207
                    errors++;
4208
                }
4209

    
4210
                if (naclp) {
4211
                    while (*naclp)
4212
                        naclp = &(*naclp)->next;
4213

    
4214
                    *naclp = nacl;
4215
                }
4216
            }
4217
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4218
            get_arg(arg, sizeof(arg), &p);
4219
            if (stream) {
4220
                av_freep(&stream->rtsp_option);
4221
                stream->rtsp_option = av_strdup(arg);
4222
            }
4223
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4224
            get_arg(arg, sizeof(arg), &p);
4225
            if (stream) {
4226
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4227
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4228
                            filename, line_num, arg);
4229
                    errors++;
4230
                }
4231
                stream->is_multicast = 1;
4232
                stream->loop = 1; /* default is looping */
4233
            }
4234
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4235
            get_arg(arg, sizeof(arg), &p);
4236
            if (stream)
4237
                stream->multicast_port = atoi(arg);
4238
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4239
            get_arg(arg, sizeof(arg), &p);
4240
            if (stream)
4241
                stream->multicast_ttl = atoi(arg);
4242
        } else if (!strcasecmp(cmd, "NoLoop")) {
4243
            if (stream)
4244
                stream->loop = 0;
4245
        } else if (!strcasecmp(cmd, "</Stream>")) {
4246
            if (!stream) {
4247
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4248
                        filename, line_num);
4249
                errors++;
4250
            } else {
4251
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4252
                    if (audio_id != CODEC_ID_NONE) {
4253
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4254
                        audio_enc.codec_id = audio_id;
4255
                        add_codec(stream, &audio_enc);
4256
                    }
4257
                    if (video_id != CODEC_ID_NONE) {
4258
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4259
                        video_enc.codec_id = video_id;
4260
                        add_codec(stream, &video_enc);
4261
                    }
4262
                }
4263
                stream = NULL;
4264
            }
4265
        } else if (!strcasecmp(cmd, "<Redirect")) {
4266
            /*********************************************/
4267
            char *q;
4268
            if (stream || feed || redirect) {
4269
                fprintf(stderr, "%s:%d: Already in a tag\n",
4270
                        filename, line_num);
4271
                errors++;
4272
            } else {
4273
                redirect = av_mallocz(sizeof(FFStream));
4274
                *last_stream = redirect;
4275
                last_stream = &redirect->next;
4276

    
4277
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4278
                q = strrchr(redirect->filename, '>');
4279
                if (*q)
4280
                    *q = '\0';
4281
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4282
            }
4283
        } else if (!strcasecmp(cmd, "URL")) {
4284
            if (redirect)
4285
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4286
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4287
            if (!redirect) {
4288
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4289
                        filename, line_num);
4290
                errors++;
4291
            } else {
4292
                if (!redirect->feed_filename[0]) {
4293
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4294
                            filename, line_num);
4295
                    errors++;
4296
                }
4297
                redirect = NULL;
4298
            }
4299
        } else if (!strcasecmp(cmd, "LoadModule")) {
4300
            get_arg(arg, sizeof(arg), &p);
4301
#ifdef HAVE_DLOPEN
4302
            load_module(arg);
4303
#else
4304
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4305
                    filename, line_num, arg);
4306
            errors++;
4307
#endif
4308
        } else {
4309
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4310
                    filename, line_num, cmd);
4311
            errors++;
4312
        }
4313
    }
4314

    
4315
    fclose(f);
4316
    if (errors)
4317
        return -1;
4318
    else
4319
        return 0;
4320
}
4321

    
4322
static void handle_child_exit(int sig)
4323
{
4324
    pid_t pid;
4325
    int status;
4326

    
4327
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4328
        FFStream *feed;
4329

    
4330
        for (feed = first_feed; feed; feed = feed->next) {
4331
            if (feed->pid == pid) {
4332
                int uptime = time(0) - feed->pid_start;
4333

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

    
4337
                if (uptime < 30)
4338
                    /* Turn off any more restarts */
4339
                    feed->child_argv = 0;
4340
            }
4341
        }
4342
    }
4343

    
4344
    need_to_start_children = 1;
4345
}
4346

    
4347
static void opt_debug()
4348
{
4349
    ffserver_debug = 1;
4350
    ffserver_daemon = 0;
4351
}
4352

    
4353
static void opt_show_help(void)
4354
{
4355
    printf("usage: ffserver [options]\n"
4356
           "Hyper fast multi format Audio/Video streaming server\n");
4357
    printf("\n");
4358
    show_help_options(options, "Main options:\n", 0, 0);
4359
}
4360

    
4361
static const OptionDef options[] = {
4362
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4363
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4364
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4365
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4366
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4367
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4368
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4369
    { NULL },
4370
};
4371

    
4372
int main(int argc, char **argv)
4373
{
4374
    struct sigaction sigact;
4375

    
4376
    av_register_all();
4377

    
4378
    show_banner();
4379

    
4380
    config_filename = "/etc/ffserver.conf";
4381

    
4382
    my_program_name = argv[0];
4383
    my_program_dir = getcwd(0, 0);
4384
    ffserver_daemon = 1;
4385

    
4386
    parse_options(argc, argv, options, NULL);
4387

    
4388
    putenv("http_proxy");               /* Kill the http_proxy */
4389

    
4390
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4391

    
4392
    /* address on which the server will handle HTTP connections */
4393
    my_http_addr.sin_family = AF_INET;
4394
    my_http_addr.sin_port = htons (8080);
4395
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4396

    
4397
    /* address on which the server will handle RTSP connections */
4398
    my_rtsp_addr.sin_family = AF_INET;
4399
    my_rtsp_addr.sin_port = htons (5454);
4400
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4401

    
4402
    nb_max_connections = 5;
4403
    max_bandwidth = 1000;
4404
    first_stream = NULL;
4405
    logfilename[0] = '\0';
4406

    
4407
    memset(&sigact, 0, sizeof(sigact));
4408
    sigact.sa_handler = handle_child_exit;
4409
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4410
    sigaction(SIGCHLD, &sigact, 0);
4411

    
4412
    if (parse_ffconfig(config_filename) < 0) {
4413
        fprintf(stderr, "Incorrect config file - exiting.\n");
4414
        exit(1);
4415
    }
4416

    
4417
    build_file_streams();
4418

    
4419
    build_feed_streams();
4420

    
4421
    compute_bandwidth();
4422

    
4423
    /* put the process in background and detach it from its TTY */
4424
    if (ffserver_daemon) {
4425
        int pid;
4426

    
4427
        pid = fork();
4428
        if (pid < 0) {
4429
            perror("fork");
4430
            exit(1);
4431
        } else if (pid > 0) {
4432
            /* parent : exit */
4433
            exit(0);
4434
        } else {
4435
            /* child */
4436
            setsid();
4437
            chdir("/");
4438
            close(0);
4439
            open("/dev/null", O_RDWR);
4440
            if (strcmp(logfilename, "-") != 0) {
4441
                close(1);
4442
                dup(0);
4443
            }
4444
            close(2);
4445
            dup(0);
4446
        }
4447
    }
4448

    
4449
    /* signal init */
4450
    signal(SIGPIPE, SIG_IGN);
4451

    
4452
    /* open log file if needed */
4453
    if (logfilename[0] != '\0') {
4454
        if (!strcmp(logfilename, "-"))
4455
            logfile = stdout;
4456
        else
4457
            logfile = fopen(logfilename, "a");
4458
    }
4459

    
4460
    if (http_server() < 0) {
4461
        fprintf(stderr, "Could not start server\n");
4462
        exit(1);
4463
    }
4464

    
4465
    return 0;
4466
}