Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ f346033e

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 "version.h"
54
#include "ffserver.h"
55
#include "cmdutils.h"
56

    
57
#undef exit
58

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

    
62
static const OptionDef options[];
63

    
64
/* maximum number of simultaneous HTTP connections */
65
#define HTTP_MAX_CONNECTIONS 2000
66

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

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

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

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

    
93
    "RTSP_WAIT_REQUEST",
94
    "RTSP_SEND_REPLY",
95
    "RTSP_SEND_PACKET",
96
};
97

    
98
#define IOBUFFER_INIT_SIZE 8192
99

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

    
104
#define SYNC_TIMEOUT (10 * 1000)
105

    
106
typedef struct {
107
    int64_t count1, count2;
108
    int64_t time1, time2;
109
} DataRateData;
110

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

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

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

    
166
    /* RTP/UDP specific */
167
    URLContext *rtp_handles[MAX_STREAMS];
168

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

    
174
static AVFrame dummy_frame;
175

    
176
/* each generated stream is described here */
177
enum StreamType {
178
    STREAM_TYPE_LIVE,
179
    STREAM_TYPE_STATUS,
180
    STREAM_TYPE_REDIRECT,
181
};
182

    
183
enum IPAddressAction {
184
    IP_ALLOW = 1,
185
    IP_DENY,
186
};
187

    
188
typedef struct IPAddressACL {
189
    struct IPAddressACL *next;
190
    enum IPAddressAction action;
191
    /* These are in host order */
192
    struct in_addr first;
193
    struct in_addr last;
194
} IPAddressACL;
195

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

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

    
244
typedef struct FeedData {
245
    long long data_count;
246
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
247
} FeedData;
248

    
249
static struct sockaddr_in my_http_addr;
250
static struct sockaddr_in my_rtsp_addr;
251

    
252
static char logfilename[1024];
253
static HTTPContext *first_http_ctx;
254
static FFStream *first_feed;   /* contains only feeds */
255
static FFStream *first_stream; /* contains all streams, including feeds */
256

    
257
static void new_connection(int server_fd, int is_rtsp);
258
static void close_connection(HTTPContext *c);
259

    
260
/* HTTP handling */
261
static int handle_connection(HTTPContext *c);
262
static int http_parse_request(HTTPContext *c);
263
static int http_send_data(HTTPContext *c);
264
static void compute_stats(HTTPContext *c);
265
static int open_input_stream(HTTPContext *c, const char *info);
266
static int http_start_receive_data(HTTPContext *c);
267
static int http_receive_data(HTTPContext *c);
268

    
269
/* RTSP handling */
270
static int rtsp_parse_request(HTTPContext *c);
271
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
272
static void rtsp_cmd_options(HTTPContext *c, const char *url);
273
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
274
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
275
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
276
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
277

    
278
/* SDP handling */
279
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
280
                                   struct in_addr my_ip);
281

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

    
290
static const char *my_program_name;
291
static const char *my_program_dir;
292

    
293
static const char *config_filename;
294
static int ffserver_debug;
295
static int ffserver_daemon;
296
static int no_launch;
297
static int need_to_start_children;
298

    
299
static int nb_max_connections;
300
static int nb_connections;
301

    
302
static int max_bandwidth;
303
static int current_bandwidth;
304

    
305
static int64_t cur_time;           // Making this global saves on passing it around everywhere
306

    
307
static AVRandomState random_state;
308

    
309
static FILE *logfile = NULL;
310

    
311
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
312
{
313
    va_list ap;
314
    va_start(ap, fmt);
315

    
316
    if (logfile) {
317
        vfprintf(logfile, fmt, ap);
318
        fflush(logfile);
319
    }
320
    va_end(ap);
321
}
322

    
323
static char *ctime1(char *buf2)
324
{
325
    time_t ti;
326
    char *p;
327

    
328
    ti = time(NULL);
329
    p = ctime(&ti);
330
    strcpy(buf2, p);
331
    p = buf2 + strlen(p) - 1;
332
    if (*p == '\n')
333
        *p = '\0';
334
    return buf2;
335
}
336

    
337
static void log_connection(HTTPContext *c)
338
{
339
    char buf2[32];
340

    
341
    if (c->suppress_log)
342
        return;
343

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

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

    
363
/* In bytes per second */
364
static int compute_datarate(DataRateData *drd, int64_t count)
365
{
366
    if (cur_time == drd->time1)
367
        return 0;
368

    
369
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
370
}
371

    
372

    
373
static void start_children(FFStream *feed)
374
{
375
    if (no_launch)
376
        return;
377

    
378
    for (; feed; feed = feed->next) {
379
        if (feed->child_argv && !feed->pid) {
380
            feed->pid_start = time(0);
381

    
382
            feed->pid = fork();
383

    
384
            if (feed->pid < 0) {
385
                fprintf(stderr, "Unable to create children\n");
386
                exit(1);
387
            }
388
            if (!feed->pid) {
389
                /* In child */
390
                char pathname[1024];
391
                char *slash;
392
                int i;
393

    
394
                for (i = 3; i < 256; i++)
395
                    close(i);
396

    
397
                if (!ffserver_debug) {
398
                    i = open("/dev/null", O_RDWR);
399
                    if (i)
400
                        dup2(i, 0);
401
                    dup2(i, 1);
402
                    dup2(i, 2);
403
                    if (i)
404
                        close(i);
405
                }
406

    
407
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
408

    
409
                slash = strrchr(pathname, '/');
410
                if (!slash)
411
                    slash = pathname;
412
                else
413
                    slash++;
414
                strcpy(slash, "ffmpeg");
415

    
416
                /* This is needed to make relative pathnames work */
417
                chdir(my_program_dir);
418

    
419
                signal(SIGPIPE, SIG_DFL);
420

    
421
                execvp(pathname, feed->child_argv);
422

    
423
                _exit(1);
424
            }
425
        }
426
    }
427
}
428

    
429
/* open a listening socket */
430
static int socket_open_listen(struct sockaddr_in *my_addr)
431
{
432
    int server_fd, tmp;
433

    
434
    server_fd = socket(AF_INET,SOCK_STREAM,0);
435
    if (server_fd < 0) {
436
        perror ("socket");
437
        return -1;
438
    }
439

    
440
    tmp = 1;
441
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
442

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

    
451
    if (listen (server_fd, 5) < 0) {
452
        perror ("listen");
453
        closesocket(server_fd);
454
        return -1;
455
    }
456
    ff_socket_nonblock(server_fd, 1);
457

    
458
    return server_fd;
459
}
460

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

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

    
477
            /* choose a port if none given */
478
            if (stream->multicast_port == 0) {
479
                stream->multicast_port = default_port;
480
                default_port += 100;
481
            }
482

    
483
            dest_addr.sin_family = AF_INET;
484
            dest_addr.sin_addr = stream->multicast_ip;
485
            dest_addr.sin_port = htons(stream->multicast_port);
486

    
487
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
488
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
489
            if (!rtp_c)
490
                continue;
491

    
492
            if (open_input_stream(rtp_c, "") < 0) {
493
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
494
                        stream->filename);
495
                continue;
496
            }
497

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

    
510
            /* change state to send data */
511
            rtp_c->state = HTTPSTATE_SEND_DATA;
512
        }
513
    }
514
}
515

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

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

    
527
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
528
    if (rtsp_server_fd < 0)
529
        return -1;
530

    
531
    http_log("ffserver started.\n");
532

    
533
    start_children(first_feed);
534

    
535
    first_http_ctx = NULL;
536
    nb_connections = 0;
537

    
538
    start_multicast();
539

    
540
    for(;;) {
541
        poll_entry = poll_table;
542
        poll_entry->fd = server_fd;
543
        poll_entry->events = POLLIN;
544
        poll_entry++;
545

    
546
        poll_entry->fd = rtsp_server_fd;
547
        poll_entry->events = POLLIN;
548
        poll_entry++;
549

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

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

    
609
        cur_time = av_gettime() / 1000;
610

    
611
        if (need_to_start_children) {
612
            need_to_start_children = 0;
613
            start_children(first_feed);
614
        }
615

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

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

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

    
643
    if (is_rtsp) {
644
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
645
        c->state = RTSPSTATE_WAIT_REQUEST;
646
    } else {
647
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
648
        c->state = HTTPSTATE_WAIT_REQUEST;
649
    }
650
}
651

    
652
static void new_connection(int server_fd, int is_rtsp)
653
{
654
    struct sockaddr_in from_addr;
655
    int fd, len;
656
    HTTPContext *c = NULL;
657

    
658
    len = sizeof(from_addr);
659
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
660
                &len);
661
    if (fd < 0)
662
        return;
663
    ff_socket_nonblock(fd, 1);
664

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

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

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

    
683
    c->next = first_http_ctx;
684
    first_http_ctx = c;
685
    nb_connections++;
686

    
687
    start_wait_request(c, is_rtsp);
688

    
689
    return;
690

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

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

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

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

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

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

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

    
752
    ctx = &c->fmt_ctx;
753

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
975
                q += 20;
976

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

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

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

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

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

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

    
1001
        p++;
1002
    }
1003

    
1004
    return 0;
1005
}
1006

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

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

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

    
1022
        /* Potential stream */
1023

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

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

    
1041
    return best;
1042
}
1043

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

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

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

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

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

    
1079
    return action_required;
1080
}
1081

    
1082

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1236
        p++;
1237
    }
1238

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

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

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

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

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

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

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

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

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

    
1314
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1315
        c->http_error = 200;
1316
        q = c->buffer;
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1321
        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");
1322
        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",
1323
            current_bandwidth, max_bandwidth);
1324
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1325

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

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

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

    
1345
            p++;
1346
        }
1347

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

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

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

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

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

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

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

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

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

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

    
1453
    stream->conns_served++;
1454

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

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

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

    
1477
                p++;
1478
            }
1479

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

    
1483
                logline += 17;
1484

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

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

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

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

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

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

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

    
1528
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1529
        goto send_stats;
1530

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1758
                parameters[0] = 0;
1759

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1988

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

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

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

    
2023
            *st = *src;
2024
            st->priv_data = 0;
2025
            st->codec->frame_number = 0; /* XXX: should be done in
2026
                                           AVStream, not in codec */
2027
            /* I'm pretty sure that this is not correct...
2028
             * However, without it, we crash
2029
             */
2030
            st->codec->coded_frame = &dummy_frame;
2031
        }
2032
        c->got_key_frame = 0;
2033

    
2034
        /* prepare header and save header data in a stream */
2035
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2036
            /* XXX: potential leak */
2037
            return -1;
2038
        }
2039
        c->fmt_ctx.pb->is_streamed = 1;
2040

    
2041
        av_set_parameters(&c->fmt_ctx, NULL);
2042
        if (av_write_header(&c->fmt_ctx) < 0)
2043
            return -1;
2044

    
2045
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2046
        c->buffer_ptr = c->pb_buffer;
2047
        c->buffer_end = c->pb_buffer + len;
2048

    
2049
        c->state = HTTPSTATE_SEND_DATA;
2050
        c->last_packet_sent = 0;
2051
        break;
2052
    case HTTPSTATE_SEND_DATA:
2053
        /* find a new packet */
2054
        {
2055
            AVPacket pkt;
2056

    
2057
            /* read a packet from the input stream */
2058
            if (c->stream->feed)
2059
                ffm_set_write_index(c->fmt_in,
2060
                                    c->stream->feed->feed_write_index,
2061
                                    c->stream->feed->feed_size);
2062

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

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

    
2163
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2164
                        if (c->is_packetized) {
2165
                            int max_packet_size;
2166
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2167
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2168
                            else
2169
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2170
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2171
                        } else {
2172
                            ret = url_open_dyn_buf(&ctx->pb);
2173
                        }
2174
                        if (ret < 0) {
2175
                            /* XXX: potential leak */
2176
                            return -1;
2177
                        }
2178
                        if (pkt.dts != AV_NOPTS_VALUE)
2179
                            pkt.dts = av_rescale_q(pkt.dts,
2180
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2181
                                ctx->streams[pkt.stream_index]->time_base);
2182
                        if (pkt.pts != AV_NOPTS_VALUE)
2183
                            pkt.pts = av_rescale_q(pkt.pts,
2184
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2185
                                ctx->streams[pkt.stream_index]->time_base);
2186
                        if (av_write_frame(ctx, &pkt))
2187
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2188

    
2189
                        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2190
                        c->cur_frame_bytes = len;
2191
                        c->buffer_ptr = c->pb_buffer;
2192
                        c->buffer_end = c->pb_buffer + len;
2193

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

    
2221
        c->last_packet_sent = 1;
2222
        break;
2223
    }
2224
    return 0;
2225
}
2226

    
2227
/* should convert the format at the same time */
2228
/* send data starting at c->buffer_ptr to the output connection
2229
   (either UDP or TCP connection) */
2230
static int http_send_data(HTTPContext *c)
2231
{
2232
    int len, ret;
2233

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

    
2263
                c->data_count += len;
2264
                update_datarate(&c->datarate, c->data_count);
2265
                if (c->stream)
2266
                    c->stream->bytes_served += len;
2267

    
2268
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2269
                    /* RTP packets are sent inside the RTSP TCP connection */
2270
                    ByteIOContext *pb;
2271
                    int interleaved_index, size;
2272
                    uint8_t header[4];
2273
                    HTTPContext *rtsp_c;
2274

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

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

    
2338
                c->data_count += len;
2339
                update_datarate(&c->datarate, c->data_count);
2340
                if (c->stream)
2341
                    c->stream->bytes_served += len;
2342
                break;
2343
            }
2344
        }
2345
    } /* for(;;) */
2346
    return 0;
2347
}
2348

    
2349
static int http_start_receive_data(HTTPContext *c)
2350
{
2351
    int fd;
2352

    
2353
    if (c->stream->feed_opened)
2354
        return -1;
2355

    
2356
    /* Don't permit writing to this one */
2357
    if (c->stream->readonly)
2358
        return -1;
2359

    
2360
    /* open feed */
2361
    fd = open(c->stream->feed_filename, O_RDWR);
2362
    if (fd < 0)
2363
        return -1;
2364
    c->feed_fd = fd;
2365

    
2366
    c->stream->feed_write_index = ffm_read_write_index(fd);
2367
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2368
    lseek(fd, 0, SEEK_SET);
2369

    
2370
    /* init buffer input */
2371
    c->buffer_ptr = c->buffer;
2372
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2373
    c->stream->feed_opened = 1;
2374
    return 0;
2375
}
2376

    
2377
static int http_receive_data(HTTPContext *c)
2378
{
2379
    HTTPContext *c1;
2380

    
2381
    if (c->buffer_end > c->buffer_ptr) {
2382
        int len;
2383

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

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

    
2408
    if (c->buffer_ptr >= c->buffer_end) {
2409
        FFStream *feed = c->stream;
2410
        /* a packet has been received : write it in the store, except
2411
           if header */
2412
        if (c->data_count > FFM_PACKET_SIZE) {
2413

    
2414
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2415
            /* XXX: use llseek or url_seek */
2416
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2417
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2418

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

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

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

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

    
2443
            memset(&s, 0, sizeof(s));
2444

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

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

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

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

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

    
2478
    return 0;
2479
 fail:
2480
    c->stream->feed_opened = 0;
2481
    close(c->feed_fd);
2482
    return -1;
2483
}
2484

    
2485
/********************************************************************/
2486
/* RTSP handling */
2487

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2674
    return strlen(*pbuffer);
2675
}
2676

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2892

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

    
2896

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

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

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

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

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

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

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

    
2954
    rtp_c->state = HTTPSTATE_SEND_DATA;
2955

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

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

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

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

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

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

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

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

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

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

    
3011

    
3012
/********************************************************************/
3013
/* RTP handling */
3014

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

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

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

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

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

    
3064
    current_bandwidth += stream->bandwidth;
3065

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3176
/********************************************************************/
3177
/* ffserver initialization */
3178

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3500
        close(fd);
3501
    }
3502
}
3503

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

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

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

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

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

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

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

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

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

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

    
3619

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

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

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

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

    
3640
    return p->id;
3641
}
3642

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

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

    
3650
    return p->id;
3651
}
3652

    
3653
/* simplistic plugin support */
3654

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

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

    
3675
    init_func();
3676
}
3677
#endif
3678

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4014
                get_arg(arg, sizeof(arg), &p);
4015

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

    
4154
            get_arg(arg, sizeof(arg), &p);
4155
            if (strcasecmp(arg, "allow") == 0)
4156
                acl.action = IP_ALLOW;
4157
            else if (strcasecmp(arg, "deny") == 0)
4158
                acl.action = IP_DENY;
4159
            else {
4160
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4161
                        filename, line_num, arg);
4162
                errors++;
4163
            }
4164

    
4165
            get_arg(arg, sizeof(arg), &p);
4166

    
4167
            if (resolve_host(&acl.first, arg) != 0) {
4168
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4169
                        filename, line_num, arg);
4170
                errors++;
4171
            } else
4172
                acl.last = acl.first;
4173

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

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

    
4184
            if (!errors) {
4185
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4186
                IPAddressACL **naclp = 0;
4187

    
4188
                acl.next = 0;
4189
                *nacl = acl;
4190

    
4191
                if (stream)
4192
                    naclp = &stream->acl;
4193
                else if (feed)
4194
                    naclp = &feed->acl;
4195
                else {
4196
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4197
                            filename, line_num);
4198
                    errors++;
4199
                }
4200

    
4201
                if (naclp) {
4202
                    while (*naclp)
4203
                        naclp = &(*naclp)->next;
4204

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

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

    
4304
    fclose(f);
4305
    if (errors)
4306
        return -1;
4307
    else
4308
        return 0;
4309
}
4310

    
4311
static void handle_child_exit(int sig)
4312
{
4313
    pid_t pid;
4314
    int status;
4315

    
4316
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4317
        FFStream *feed;
4318

    
4319
        for (feed = first_feed; feed; feed = feed->next) {
4320
            if (feed->pid == pid) {
4321
                int uptime = time(0) - feed->pid_start;
4322

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

    
4326
                if (uptime < 30)
4327
                    /* Turn off any more restarts */
4328
                    feed->child_argv = 0;
4329
            }
4330
        }
4331
    }
4332

    
4333
    need_to_start_children = 1;
4334
}
4335

    
4336
static void opt_debug()
4337
{
4338
    ffserver_debug = 1;
4339
    ffserver_daemon = 0;
4340
}
4341

    
4342
static void opt_show_help(void)
4343
{
4344
    printf("usage: ffserver [options]\n"
4345
           "Hyper fast multi format Audio/Video streaming server\n");
4346
    printf("\n");
4347
    show_help_options(options, "Main options:\n", 0, 0);
4348
}
4349

    
4350
static const OptionDef options[] = {
4351
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4352
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4353
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4354
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4355
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4356
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4357
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4358
    { NULL },
4359
};
4360

    
4361
int main(int argc, char **argv)
4362
{
4363
    struct sigaction sigact;
4364

    
4365
    av_register_all();
4366

    
4367
    show_banner(program_name, program_birth_year);
4368

    
4369
    config_filename = "/etc/ffserver.conf";
4370

    
4371
    my_program_name = argv[0];
4372
    my_program_dir = getcwd(0, 0);
4373
    ffserver_daemon = 1;
4374

    
4375
    parse_options(argc, argv, options, NULL);
4376

    
4377
    putenv("http_proxy");               /* Kill the http_proxy */
4378

    
4379
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4380

    
4381
    /* address on which the server will handle HTTP connections */
4382
    my_http_addr.sin_family = AF_INET;
4383
    my_http_addr.sin_port = htons (8080);
4384
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4385

    
4386
    /* address on which the server will handle RTSP connections */
4387
    my_rtsp_addr.sin_family = AF_INET;
4388
    my_rtsp_addr.sin_port = htons (5454);
4389
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4390

    
4391
    nb_max_connections = 5;
4392
    max_bandwidth = 1000;
4393
    first_stream = NULL;
4394
    logfilename[0] = '\0';
4395

    
4396
    memset(&sigact, 0, sizeof(sigact));
4397
    sigact.sa_handler = handle_child_exit;
4398
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4399
    sigaction(SIGCHLD, &sigact, 0);
4400

    
4401
    if (parse_ffconfig(config_filename) < 0) {
4402
        fprintf(stderr, "Incorrect config file - exiting.\n");
4403
        exit(1);
4404
    }
4405

    
4406
    build_file_streams();
4407

    
4408
    build_feed_streams();
4409

    
4410
    compute_bandwidth();
4411

    
4412
    /* put the process in background and detach it from its TTY */
4413
    if (ffserver_daemon) {
4414
        int pid;
4415

    
4416
        pid = fork();
4417
        if (pid < 0) {
4418
            perror("fork");
4419
            exit(1);
4420
        } else if (pid > 0) {
4421
            /* parent : exit */
4422
            exit(0);
4423
        } else {
4424
            /* child */
4425
            setsid();
4426
            chdir("/");
4427
            close(0);
4428
            open("/dev/null", O_RDWR);
4429
            if (strcmp(logfilename, "-") != 0) {
4430
                close(1);
4431
                dup(0);
4432
            }
4433
            close(2);
4434
            dup(0);
4435
        }
4436
    }
4437

    
4438
    /* signal init */
4439
    signal(SIGPIPE, SIG_IGN);
4440

    
4441
    /* open log file if needed */
4442
    if (logfilename[0] != '\0') {
4443
        if (!strcmp(logfilename, "-"))
4444
            logfile = stdout;
4445
        else
4446
            logfile = fopen(logfilename, "a");
4447
    }
4448

    
4449
    if (http_server() < 0) {
4450
        fprintf(stderr, "Could not start server\n");
4451
        exit(1);
4452
    }
4453

    
4454
    return 0;
4455
}