Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ c1593d0e

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
                            pkt.stream_index = i;
2103
                            if (pkt.flags & PKT_FLAG_KEY)
2104
                                c->got_key_frame |= 1 << i;
2105
                            /* See if we have all the key frames, then
2106
                             * we start to send. This logic is not quite
2107
                             * right, but it works for the case of a
2108
                             * single video stream with one or more
2109
                             * audio streams (for which every frame is
2110
                             * typically a key frame).
2111
                             */
2112
                            if (!c->stream->send_on_key ||
2113
                                ((c->got_key_frame + 1) >> c->stream->nb_streams))
2114
                                goto send_it;
2115
                        }
2116
                    }
2117
                } else {
2118
                    AVCodecContext *codec;
2119

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

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

    
2182
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2183
                    c->cur_frame_bytes = len;
2184
                    c->buffer_ptr = c->pb_buffer;
2185
                    c->buffer_end = c->pb_buffer + len;
2186

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

    
2214
        c->last_packet_sent = 1;
2215
        break;
2216
    }
2217
    return 0;
2218
}
2219

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

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

    
2256
                c->data_count += len;
2257
                update_datarate(&c->datarate, c->data_count);
2258
                if (c->stream)
2259
                    c->stream->bytes_served += len;
2260

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

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

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

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

    
2342
static int http_start_receive_data(HTTPContext *c)
2343
{
2344
    int fd;
2345

    
2346
    if (c->stream->feed_opened)
2347
        return -1;
2348

    
2349
    /* Don't permit writing to this one */
2350
    if (c->stream->readonly)
2351
        return -1;
2352

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

    
2361
    c->stream->feed_write_index = ffm_read_write_index(fd);
2362
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2363
    lseek(fd, 0, SEEK_SET);
2364

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

    
2372
static int http_receive_data(HTTPContext *c)
2373
{
2374
    HTTPContext *c1;
2375

    
2376
    if (c->buffer_end > c->buffer_ptr) {
2377
        int len;
2378

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

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

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

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

    
2417
            feed->feed_write_index += FFM_PACKET_SIZE;
2418
            /* update file size */
2419
            if (feed->feed_write_index > c->stream->feed_size)
2420
                feed->feed_size = feed->feed_write_index;
2421

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

    
2426
            /* write index */
2427
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2428

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

    
2441
            memset(&s, 0, sizeof(s));
2442

    
2443
            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2444
            s.pb->is_streamed = 1;
2445

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

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

    
2458
            if (fmt_in->read_header(&s, 0) < 0) {
2459
                av_freep(&s.priv_data);
2460
                goto fail;
2461
            }
2462

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

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

    
2489
/********************************************************************/
2490
/* RTSP handling */
2491

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

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

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

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

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

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

    
2567
    c->buffer_ptr[0] = '\0';
2568
    p = c->buffer;
2569

    
2570
    get_word(cmd, sizeof(cmd), &p);
2571
    get_word(url, sizeof(url), &p);
2572
    get_word(protocol, sizeof(protocol), &p);
2573

    
2574
    av_strlcpy(c->method, cmd, sizeof(c->method));
2575
    av_strlcpy(c->url, url, sizeof(c->url));
2576
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2577

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

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

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

    
2616
    /* handle sequence number */
2617
    c->seq = header->seq;
2618

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

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

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

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

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

    
2678
    return strlen(*pbuffer);
2679
}
2680

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

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

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

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

    
2716
 found:
2717
    /* prepare the media description in sdp format */
2718

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

    
2734
static HTTPContext *find_rtp_session(const char *session_id)
2735
{
2736
    HTTPContext *c;
2737

    
2738
    if (session_id[0] == '\0')
2739
        return NULL;
2740

    
2741
    for(c = first_http_ctx; c != NULL; c = c->next) {
2742
        if (!strcmp(c->session_id, session_id))
2743
            return c;
2744
    }
2745
    return NULL;
2746
}
2747

    
2748
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2749
{
2750
    RTSPTransportField *th;
2751
    int i;
2752

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2896

    
2897
    url_fprintf(c->pb, "\r\n");
2898
}
2899

    
2900

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

    
2912
    rtp_c = find_rtp_session(session_id);
2913
    if (!rtp_c)
2914
        return NULL;
2915

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

    
2933
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2934
{
2935
    HTTPContext *rtp_c;
2936

    
2937
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2938
    if (!rtp_c) {
2939
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2940
        return;
2941
    }
2942

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

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

    
2958
    rtp_c->state = HTTPSTATE_SEND_DATA;
2959

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

    
2967
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2968
{
2969
    HTTPContext *rtp_c;
2970

    
2971
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2972
    if (!rtp_c) {
2973
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2974
        return;
2975
    }
2976

    
2977
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2978
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2979
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2980
        return;
2981
    }
2982

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

    
2992
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2993
{
2994
    HTTPContext *rtp_c;
2995
    char session_id[32];
2996

    
2997
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2998
    if (!rtp_c) {
2999
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3000
        return;
3001
    }
3002

    
3003
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3004

    
3005
    /* abort the session */
3006
    close_connection(rtp_c);
3007

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

    
3015

    
3016
/********************************************************************/
3017
/* RTP handling */
3018

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

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

    
3031
    /* add a new connection */
3032
    c = av_mallocz(sizeof(HTTPContext));
3033
    if (!c)
3034
        goto fail;
3035

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

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

    
3068
    current_bandwidth += stream->bandwidth;
3069

    
3070
    c->next = first_http_ctx;
3071
    first_http_ctx = c;
3072
    return c;
3073

    
3074
 fail:
3075
    if (c) {
3076
        av_free(c->buffer);
3077
        av_free(c);
3078
    }
3079
    return NULL;
3080
}
3081

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

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

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

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

    
3119
    /* build destination RTP address */
3120
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3121

    
3122
    switch(c->rtp_protocol) {
3123
    case RTSP_PROTOCOL_RTP_UDP:
3124
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3125
        /* RTP/UDP case */
3126

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

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

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

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

    
3176
    c->rtp_ctx[stream_index] = ctx;
3177
    return 0;
3178
}
3179

    
3180
/********************************************************************/
3181
/* ffserver initialization */
3182

    
3183
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3184
{
3185
    AVStream *fst;
3186

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

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

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

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

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

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

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

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

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

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

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

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

    
3343
                for(i=0;i<infile->nb_streams;i++)
3344
                    add_av_stream1(stream, infile->streams[i]->codec);
3345

    
3346
                av_close_input_file(infile);
3347
            }
3348
        }
3349
    }
3350
}
3351

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

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

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

    
3381
    /* create feed files if needed */
3382
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3383
        int fd;
3384

    
3385
        if (url_exist(feed->feed_filename)) {
3386
            /* See if it matches */
3387
            AVFormatContext *s;
3388
            int matches = 0;
3389

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

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

    
3407
                            ccf = sf->codec;
3408
                            ccs = ss->codec;
3409
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3410

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

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

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

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

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

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

    
3503
        close(fd);
3504
    }
3505
}
3506

    
3507
/* compute the bandwidth used by each stream */
3508
static void compute_bandwidth(void)
3509
{
3510
    int bandwidth, i;
3511
    FFStream *stream;
3512

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

    
3530
static void get_arg(char *buf, int buf_size, const char **pp)
3531
{
3532
    const char *p;
3533
    char *q;
3534
    int quote;
3535

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

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

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

    
3601
        if (!av->nsse_weight)
3602
            av->nsse_weight = 8;
3603

    
3604
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3605
        av->me_method = ME_EPZS;
3606
        av->rc_buffer_aggressivity = 1.0;
3607

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

    
3619
        if (av->rc_max_rate && !av->rc_buffer_size) {
3620
            av->rc_buffer_size = av->rc_max_rate;
3621
        }
3622

    
3623

    
3624
        break;
3625
    default:
3626
        abort();
3627
    }
3628

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

    
3637
static int opt_audio_codec(const char *arg)
3638
{
3639
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3640

    
3641
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3642
        return CODEC_ID_NONE;
3643

    
3644
    return p->id;
3645
}
3646

    
3647
static int opt_video_codec(const char *arg)
3648
{
3649
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3650

    
3651
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3652
        return CODEC_ID_NONE;
3653

    
3654
    return p->id;
3655
}
3656

    
3657
/* simplistic plugin support */
3658

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

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

    
3679
    init_func();
3680
}
3681
#endif
3682

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

    
3696
    f = fopen(filename, "r");
3697
    if (!f) {
3698
        perror(filename);
3699
        return -1;
3700
    }
3701

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

    
3723
        get_arg(cmd, sizeof(cmd), &p);
3724

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

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

    
3812
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3813

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

    
3819
                    feed->child_argv[i] = av_strdup(arg);
3820
                }
3821

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

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

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

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

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

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

    
4020
                get_arg(arg, sizeof(arg), &p);
4021

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

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

    
4177
            get_arg(arg, sizeof(arg), &p);
4178

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

    
4186
            get_arg(arg, sizeof(arg), &p);
4187

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

    
4196
            if (!errors) {
4197
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4198
                IPAddressACL **naclp = 0;
4199

    
4200
                acl.next = 0;
4201
                *nacl = acl;
4202

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

    
4213
                if (naclp) {
4214
                    while (*naclp)
4215
                        naclp = &(*naclp)->next;
4216

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

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

    
4318
    fclose(f);
4319
    if (errors)
4320
        return -1;
4321
    else
4322
        return 0;
4323
}
4324

    
4325
static void handle_child_exit(int sig)
4326
{
4327
    pid_t pid;
4328
    int status;
4329

    
4330
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4331
        FFStream *feed;
4332

    
4333
        for (feed = first_feed; feed; feed = feed->next) {
4334
            if (feed->pid == pid) {
4335
                int uptime = time(0) - feed->pid_start;
4336

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

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

    
4347
    need_to_start_children = 1;
4348
}
4349

    
4350
static void opt_debug()
4351
{
4352
    ffserver_debug = 1;
4353
    ffserver_daemon = 0;
4354
}
4355

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

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

    
4375
int main(int argc, char **argv)
4376
{
4377
    struct sigaction sigact;
4378

    
4379
    av_register_all();
4380

    
4381
    show_banner();
4382

    
4383
    config_filename = "/etc/ffserver.conf";
4384

    
4385
    my_program_name = argv[0];
4386
    my_program_dir = getcwd(0, 0);
4387
    ffserver_daemon = 1;
4388

    
4389
    parse_options(argc, argv, options, NULL);
4390

    
4391
    putenv("http_proxy");               /* Kill the http_proxy */
4392

    
4393
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4394

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

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

    
4405
    nb_max_connections = 5;
4406
    max_bandwidth = 1000;
4407
    first_stream = NULL;
4408
    logfilename[0] = '\0';
4409

    
4410
    memset(&sigact, 0, sizeof(sigact));
4411
    sigact.sa_handler = handle_child_exit;
4412
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4413
    sigaction(SIGCHLD, &sigact, 0);
4414

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

    
4420
    build_file_streams();
4421

    
4422
    build_feed_streams();
4423

    
4424
    compute_bandwidth();
4425

    
4426
    /* put the process in background and detach it from its TTY */
4427
    if (ffserver_daemon) {
4428
        int pid;
4429

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

    
4452
    /* signal init */
4453
    signal(SIGPIPE, SIG_IGN);
4454

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

    
4463
    if (http_server() < 0) {
4464
        fprintf(stderr, "Could not start server\n");
4465
        exit(1);
4466
    }
4467

    
4468
    return 0;
4469
}