Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3b371676

History | View | Annotate | Download (147 KB)

1
/*
2
 * Multiple format streaming server
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

    
22
#include "config.h"
23
#ifndef HAVE_CLOSESOCKET
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "libavutil/random.h"
29
#include "libavutil/avstring.h"
30
#include "libavformat/avformat.h"
31
#include "libavformat/network.h"
32
#include "libavformat/os_support.h"
33
#include "libavformat/rtp.h"
34
#include "libavformat/rtsp.h"
35

    
36
#include <stdarg.h>
37
#include <unistd.h>
38
#include <fcntl.h>
39
#include <sys/ioctl.h>
40
#ifdef HAVE_POLL_H
41
#include <poll.h>
42
#endif
43
#include <errno.h>
44
#include <sys/time.h>
45
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
46
#include <time.h>
47
#include <sys/wait.h>
48
#include <signal.h>
49
#ifdef HAVE_DLFCN_H
50
#include <dlfcn.h>
51
#endif
52

    
53
#include "cmdutils.h"
54

    
55
#undef exit
56

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

    
60
static const OptionDef options[];
61

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

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

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

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

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

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

    
96
#define IOBUFFER_INIT_SIZE 8192
97

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

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
295
static int nb_max_connections;
296
static int nb_connections;
297

    
298
static int max_bandwidth;
299
static int current_bandwidth;
300

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

    
303
static AVRandomState random_state;
304

    
305
static FILE *logfile = NULL;
306

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

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

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

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

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

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

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

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

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

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

    
368

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

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

    
378
            feed->pid = fork();
379

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

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

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

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

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

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

    
415
                signal(SIGPIPE, SIG_DFL);
416

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

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

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

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

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

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

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

    
454
    return server_fd;
455
}
456

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

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

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

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

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

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

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

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

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

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

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

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

    
529
    start_children(first_feed);
530

    
531
    first_http_ctx = NULL;
532
    nb_connections = 0;
533

    
534
    start_multicast();
535

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

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

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

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

    
605
        cur_time = av_gettime() / 1000;
606

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

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

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

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

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

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

    
654
    len = sizeof(from_addr);
655
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
656
                &len);
657
    if (fd < 0)
658
        return;
659
    ff_socket_nonblock(fd, 1);
660

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

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

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

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

    
683
    start_wait_request(c, is_rtsp);
684

    
685
    return;
686

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

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

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

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

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

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

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

    
748
    ctx = &c->fmt_ctx;
749

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
971
                q += 20;
972

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

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

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

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

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

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

    
997
        p++;
998
    }
999

    
1000
    return 0;
1001
}
1002

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

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

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

    
1018
        /* Potential stream */
1019

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

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

    
1037
    return best;
1038
}
1039

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

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

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

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

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

    
1075
    return action_required;
1076
}
1077

    
1078

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1232
        p++;
1233
    }
1234

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1341
            p++;
1342
        }
1343

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

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

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

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

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

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

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

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

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

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

    
1449
    stream->conns_served++;
1450

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

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

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

    
1473
                p++;
1474
            }
1475

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

    
1479
                logline += 17;
1480

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

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

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

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

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

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

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

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

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

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

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

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

    
1547
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1548
    }
1549
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1550
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1551

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

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

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

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

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

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

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

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

    
1613
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1614
    if (c->stream->feed_filename)
1615
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1616
    url_fprintf(pb, "</HEAD>\n<BODY>");
1617
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1618
    /* format status */
1619
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1620
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1621
    url_fprintf(pb, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n");
1622
    stream = first_stream;
1623
    while (stream != NULL) {
1624
        char sfilename[1024];
1625
        char *eosf;
1626

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

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

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

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

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

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

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

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

    
1744
                url_fprintf(pb, "<p>");
1745
            }
1746
            url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1747

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

    
1754
                parameters[0] = 0;
1755

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

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

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

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

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

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

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

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

    
1817
    url_fprintf(pb, "<TABLE>\n");
1818
    url_fprintf(pb, "<TR><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1819
    c1 = first_http_ctx;
1820
    i = 0;
1821
    while (c1 != NULL) {
1822
        int bitrate;
1823
        int j;
1824

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1984

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

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

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

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

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

    
2033
        av_set_parameters(&c->fmt_ctx, NULL);
2034
        if (av_write_header(&c->fmt_ctx) < 0)
2035
            return -1;
2036

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

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

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

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

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

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

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

    
2209
        c->last_packet_sent = 1;
2210
        break;
2211
    }
2212
    return 0;
2213
}
2214

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

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

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

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

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

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

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

    
2337
static int http_start_receive_data(HTTPContext *c)
2338
{
2339
    int fd;
2340

    
2341
    if (c->stream->feed_opened)
2342
        return -1;
2343

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

    
2348
    /* open feed */
2349
    fd = open(c->stream->feed_filename, O_RDWR);
2350
    if (fd < 0)
2351
        return -1;
2352
    c->feed_fd = fd;
2353

    
2354
    c->stream->feed_write_index = ffm_read_write_index(fd);
2355
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2356
    lseek(fd, 0, SEEK_SET);
2357

    
2358
    /* init buffer input */
2359
    c->buffer_ptr = c->buffer;
2360
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2361
    c->stream->feed_opened = 1;
2362
    return 0;
2363
}
2364

    
2365
static int http_receive_data(HTTPContext *c)
2366
{
2367
    HTTPContext *c1;
2368

    
2369
    if (c->buffer_end > c->buffer_ptr) {
2370
        int len;
2371

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

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

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

    
2402
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2403
            /* XXX: use llseek or url_seek */
2404
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2405
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2406

    
2407
            feed->feed_write_index += FFM_PACKET_SIZE;
2408
            /* update file size */
2409
            if (feed->feed_write_index > c->stream->feed_size)
2410
                feed->feed_size = feed->feed_write_index;
2411

    
2412
            /* handle wrap around if max file size reached */
2413
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2414
                feed->feed_write_index = FFM_PACKET_SIZE;
2415

    
2416
            /* write index */
2417
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2418

    
2419
            /* wake up any waiting connections */
2420
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2421
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2422
                    c1->stream->feed == c->stream->feed)
2423
                    c1->state = HTTPSTATE_SEND_DATA;
2424
            }
2425
        } else {
2426
            /* We have a header in our hands that contains useful data */
2427
            AVFormatContext s;
2428
            AVInputFormat *fmt_in;
2429
            int i;
2430

    
2431
            memset(&s, 0, sizeof(s));
2432

    
2433
            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2434
            s.pb->is_streamed = 1;
2435

    
2436
            /* use feed output format name to find corresponding input format */
2437
            fmt_in = av_find_input_format(feed->fmt->name);
2438
            if (!fmt_in)
2439
                goto fail;
2440

    
2441
            if (fmt_in->priv_data_size > 0) {
2442
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2443
                if (!s.priv_data)
2444
                    goto fail;
2445
            } else
2446
                s.priv_data = NULL;
2447

    
2448
            if (fmt_in->read_header(&s, 0) < 0) {
2449
                av_freep(&s.priv_data);
2450
                goto fail;
2451
            }
2452

    
2453
            /* Now we have the actual streams */
2454
            if (s.nb_streams != feed->nb_streams) {
2455
                av_freep(&s.priv_data);
2456
                goto fail;
2457
            }
2458
            for (i = 0; i < s.nb_streams; i++)
2459
                memcpy(feed->streams[i]->codec,
2460
                       s.streams[i]->codec, sizeof(AVCodecContext));
2461
            av_freep(&s.priv_data);
2462
        }
2463
        c->buffer_ptr = c->buffer;
2464
    }
2465

    
2466
    return 0;
2467
 fail:
2468
    c->stream->feed_opened = 0;
2469
    close(c->feed_fd);
2470
    return -1;
2471
}
2472

    
2473
/********************************************************************/
2474
/* RTSP handling */
2475

    
2476
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2477
{
2478
    const char *str;
2479
    time_t ti;
2480
    char *p;
2481
    char buf2[32];
2482

    
2483
    switch(error_number) {
2484
    case RTSP_STATUS_OK:
2485
        str = "OK";
2486
        break;
2487
    case RTSP_STATUS_METHOD:
2488
        str = "Method Not Allowed";
2489
        break;
2490
    case RTSP_STATUS_BANDWIDTH:
2491
        str = "Not Enough Bandwidth";
2492
        break;
2493
    case RTSP_STATUS_SESSION:
2494
        str = "Session Not Found";
2495
        break;
2496
    case RTSP_STATUS_STATE:
2497
        str = "Method Not Valid in This State";
2498
        break;
2499
    case RTSP_STATUS_AGGREGATE:
2500
        str = "Aggregate operation not allowed";
2501
        break;
2502
    case RTSP_STATUS_ONLY_AGGREGATE:
2503
        str = "Only aggregate operation allowed";
2504
        break;
2505
    case RTSP_STATUS_TRANSPORT:
2506
        str = "Unsupported transport";
2507
        break;
2508
    case RTSP_STATUS_INTERNAL:
2509
        str = "Internal Server Error";
2510
        break;
2511
    case RTSP_STATUS_SERVICE:
2512
        str = "Service Unavailable";
2513
        break;
2514
    case RTSP_STATUS_VERSION:
2515
        str = "RTSP Version not supported";
2516
        break;
2517
    default:
2518
        str = "Unknown Error";
2519
        break;
2520
    }
2521

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

    
2525
    /* output GMT time */
2526
    ti = time(NULL);
2527
    p = ctime(&ti);
2528
    strcpy(buf2, p);
2529
    p = buf2 + strlen(p) - 1;
2530
    if (*p == '\n')
2531
        *p = '\0';
2532
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2533
}
2534

    
2535
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2536
{
2537
    rtsp_reply_header(c, error_number);
2538
    url_fprintf(c->pb, "\r\n");
2539
}
2540

    
2541
static int rtsp_parse_request(HTTPContext *c)
2542
{
2543
    const char *p, *p1, *p2;
2544
    char cmd[32];
2545
    char url[1024];
2546
    char protocol[32];
2547
    char line[1024];
2548
    int len;
2549
    RTSPHeader header1, *header = &header1;
2550

    
2551
    c->buffer_ptr[0] = '\0';
2552
    p = c->buffer;
2553

    
2554
    get_word(cmd, sizeof(cmd), &p);
2555
    get_word(url, sizeof(url), &p);
2556
    get_word(protocol, sizeof(protocol), &p);
2557

    
2558
    av_strlcpy(c->method, cmd, sizeof(c->method));
2559
    av_strlcpy(c->url, url, sizeof(c->url));
2560
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2561

    
2562
    if (url_open_dyn_buf(&c->pb) < 0) {
2563
        /* XXX: cannot do more */
2564
        c->pb = NULL; /* safety */
2565
        return -1;
2566
    }
2567

    
2568
    /* check version name */
2569
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2570
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2571
        goto the_end;
2572
    }
2573

    
2574
    /* parse each header line */
2575
    memset(header, 0, sizeof(RTSPHeader));
2576
    /* skip to next line */
2577
    while (*p != '\n' && *p != '\0')
2578
        p++;
2579
    if (*p == '\n')
2580
        p++;
2581
    while (*p != '\0') {
2582
        p1 = strchr(p, '\n');
2583
        if (!p1)
2584
            break;
2585
        p2 = p1;
2586
        if (p2 > p && p2[-1] == '\r')
2587
            p2--;
2588
        /* skip empty line */
2589
        if (p2 == p)
2590
            break;
2591
        len = p2 - p;
2592
        if (len > sizeof(line) - 1)
2593
            len = sizeof(line) - 1;
2594
        memcpy(line, p, len);
2595
        line[len] = '\0';
2596
        rtsp_parse_line(header, line);
2597
        p = p1 + 1;
2598
    }
2599

    
2600
    /* handle sequence number */
2601
    c->seq = header->seq;
2602

    
2603
    if (!strcmp(cmd, "DESCRIBE"))
2604
        rtsp_cmd_describe(c, url);
2605
    else if (!strcmp(cmd, "OPTIONS"))
2606
        rtsp_cmd_options(c, url);
2607
    else if (!strcmp(cmd, "SETUP"))
2608
        rtsp_cmd_setup(c, url, header);
2609
    else if (!strcmp(cmd, "PLAY"))
2610
        rtsp_cmd_play(c, url, header);
2611
    else if (!strcmp(cmd, "PAUSE"))
2612
        rtsp_cmd_pause(c, url, header);
2613
    else if (!strcmp(cmd, "TEARDOWN"))
2614
        rtsp_cmd_teardown(c, url, header);
2615
    else
2616
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2617

    
2618
 the_end:
2619
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2620
    c->pb = NULL; /* safety */
2621
    if (len < 0) {
2622
        /* XXX: cannot do more */
2623
        return -1;
2624
    }
2625
    c->buffer_ptr = c->pb_buffer;
2626
    c->buffer_end = c->pb_buffer + len;
2627
    c->state = RTSPSTATE_SEND_REPLY;
2628
    return 0;
2629
}
2630

    
2631
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2632
                                   struct in_addr my_ip)
2633
{
2634
    AVFormatContext *avc;
2635
    AVStream avs[MAX_STREAMS];
2636
    int i;
2637

    
2638
    avc =  av_alloc_format_context();
2639
    if (avc == NULL) {
2640
        return -1;
2641
    }
2642
    if (stream->title[0] != 0) {
2643
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2644
    } else {
2645
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2646
    }
2647
    avc->nb_streams = stream->nb_streams;
2648
    if (stream->is_multicast) {
2649
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2650
                 inet_ntoa(stream->multicast_ip),
2651
                 stream->multicast_port, stream->multicast_ttl);
2652
    }
2653

    
2654
    for(i = 0; i < stream->nb_streams; i++) {
2655
        avc->streams[i] = &avs[i];
2656
        avc->streams[i]->codec = stream->streams[i]->codec;
2657
    }
2658
    *pbuffer = av_mallocz(2048);
2659
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2660
    av_free(avc);
2661

    
2662
    return strlen(*pbuffer);
2663
}
2664

    
2665
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2666
{
2667
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2668
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2669
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2670
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2671
    url_fprintf(c->pb, "\r\n");
2672
}
2673

    
2674
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2675
{
2676
    FFStream *stream;
2677
    char path1[1024];
2678
    const char *path;
2679
    uint8_t *content;
2680
    int content_length, len;
2681
    struct sockaddr_in my_addr;
2682

    
2683
    /* find which url is asked */
2684
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2685
    path = path1;
2686
    if (*path == '/')
2687
        path++;
2688

    
2689
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2690
        if (!stream->is_feed &&
2691
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2692
            !strcmp(path, stream->filename)) {
2693
            goto found;
2694
        }
2695
    }
2696
    /* no stream found */
2697
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2698
    return;
2699

    
2700
 found:
2701
    /* prepare the media description in sdp format */
2702

    
2703
    /* get the host IP */
2704
    len = sizeof(my_addr);
2705
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2706
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2707
    if (content_length < 0) {
2708
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2709
        return;
2710
    }
2711
    rtsp_reply_header(c, RTSP_STATUS_OK);
2712
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2713
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2714
    url_fprintf(c->pb, "\r\n");
2715
    put_buffer(c->pb, content, content_length);
2716
}
2717

    
2718
static HTTPContext *find_rtp_session(const char *session_id)
2719
{
2720
    HTTPContext *c;
2721

    
2722
    if (session_id[0] == '\0')
2723
        return NULL;
2724

    
2725
    for(c = first_http_ctx; c != NULL; c = c->next) {
2726
        if (!strcmp(c->session_id, session_id))
2727
            return c;
2728
    }
2729
    return NULL;
2730
}
2731

    
2732
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2733
{
2734
    RTSPTransportField *th;
2735
    int i;
2736

    
2737
    for(i=0;i<h->nb_transports;i++) {
2738
        th = &h->transports[i];
2739
        if (th->protocol == protocol)
2740
            return th;
2741
    }
2742
    return NULL;
2743
}
2744

    
2745
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2746
                           RTSPHeader *h)
2747
{
2748
    FFStream *stream;
2749
    int stream_index, port;
2750
    char buf[1024];
2751
    char path1[1024];
2752
    const char *path;
2753
    HTTPContext *rtp_c;
2754
    RTSPTransportField *th;
2755
    struct sockaddr_in dest_addr;
2756
    RTSPActionServerSetup setup;
2757

    
2758
    /* find which url is asked */
2759
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2760
    path = path1;
2761
    if (*path == '/')
2762
        path++;
2763

    
2764
    /* now check each stream */
2765
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2766
        if (!stream->is_feed &&
2767
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2768
            /* accept aggregate filenames only if single stream */
2769
            if (!strcmp(path, stream->filename)) {
2770
                if (stream->nb_streams != 1) {
2771
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2772
                    return;
2773
                }
2774
                stream_index = 0;
2775
                goto found;
2776
            }
2777

    
2778
            for(stream_index = 0; stream_index < stream->nb_streams;
2779
                stream_index++) {
2780
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2781
                         stream->filename, stream_index);
2782
                if (!strcmp(path, buf))
2783
                    goto found;
2784
            }
2785
        }
2786
    }
2787
    /* no stream found */
2788
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2789
    return;
2790
 found:
2791

    
2792
    /* generate session id if needed */
2793
    if (h->session_id[0] == '\0')
2794
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2795
                 av_random(&random_state), av_random(&random_state));
2796

    
2797
    /* find rtp session, and create it if none found */
2798
    rtp_c = find_rtp_session(h->session_id);
2799
    if (!rtp_c) {
2800
        /* always prefer UDP */
2801
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2802
        if (!th) {
2803
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2804
            if (!th) {
2805
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2806
                return;
2807
            }
2808
        }
2809

    
2810
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2811
                                   th->protocol);
2812
        if (!rtp_c) {
2813
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2814
            return;
2815
        }
2816

    
2817
        /* open input stream */
2818
        if (open_input_stream(rtp_c, "") < 0) {
2819
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2820
            return;
2821
        }
2822
    }
2823

    
2824
    /* test if stream is OK (test needed because several SETUP needs
2825
       to be done for a given file) */
2826
    if (rtp_c->stream != stream) {
2827
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2828
        return;
2829
    }
2830

    
2831
    /* test if stream is already set up */
2832
    if (rtp_c->rtp_ctx[stream_index]) {
2833
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2834
        return;
2835
    }
2836

    
2837
    /* check transport */
2838
    th = find_transport(h, rtp_c->rtp_protocol);
2839
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2840
                th->client_port_min <= 0)) {
2841
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2842
        return;
2843
    }
2844

    
2845
    /* setup default options */
2846
    setup.transport_option[0] = '\0';
2847
    dest_addr = rtp_c->from_addr;
2848
    dest_addr.sin_port = htons(th->client_port_min);
2849

    
2850
    /* setup stream */
2851
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2852
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2853
        return;
2854
    }
2855

    
2856
    /* now everything is OK, so we can send the connection parameters */
2857
    rtsp_reply_header(c, RTSP_STATUS_OK);
2858
    /* session ID */
2859
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2860

    
2861
    switch(rtp_c->rtp_protocol) {
2862
    case RTSP_PROTOCOL_RTP_UDP:
2863
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2864
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2865
                    "client_port=%d-%d;server_port=%d-%d",
2866
                    th->client_port_min, th->client_port_min + 1,
2867
                    port, port + 1);
2868
        break;
2869
    case RTSP_PROTOCOL_RTP_TCP:
2870
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2871
                    stream_index * 2, stream_index * 2 + 1);
2872
        break;
2873
    default:
2874
        break;
2875
    }
2876
    if (setup.transport_option[0] != '\0')
2877
        url_fprintf(c->pb, ";%s", setup.transport_option);
2878
    url_fprintf(c->pb, "\r\n");
2879

    
2880

    
2881
    url_fprintf(c->pb, "\r\n");
2882
}
2883

    
2884

    
2885
/* find an rtp connection by using the session ID. Check consistency
2886
   with filename */
2887
static HTTPContext *find_rtp_session_with_url(const char *url,
2888
                                              const char *session_id)
2889
{
2890
    HTTPContext *rtp_c;
2891
    char path1[1024];
2892
    const char *path;
2893
    char buf[1024];
2894
    int s;
2895

    
2896
    rtp_c = find_rtp_session(session_id);
2897
    if (!rtp_c)
2898
        return NULL;
2899

    
2900
    /* find which url is asked */
2901
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2902
    path = path1;
2903
    if (*path == '/')
2904
        path++;
2905
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2906
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2907
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2908
        rtp_c->stream->filename, s);
2909
      if(!strncmp(path, buf, sizeof(buf))) {
2910
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2911
        return rtp_c;
2912
      }
2913
    }
2914
    return NULL;
2915
}
2916

    
2917
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2918
{
2919
    HTTPContext *rtp_c;
2920

    
2921
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2922
    if (!rtp_c) {
2923
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2924
        return;
2925
    }
2926

    
2927
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2928
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2929
        rtp_c->state != HTTPSTATE_READY) {
2930
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2931
        return;
2932
    }
2933

    
2934
#if 0
2935
    /* XXX: seek in stream */
2936
    if (h->range_start != AV_NOPTS_VALUE) {
2937
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2938
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2939
    }
2940
#endif
2941

    
2942
    rtp_c->state = HTTPSTATE_SEND_DATA;
2943

    
2944
    /* now everything is OK, so we can send the connection parameters */
2945
    rtsp_reply_header(c, RTSP_STATUS_OK);
2946
    /* session ID */
2947
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2948
    url_fprintf(c->pb, "\r\n");
2949
}
2950

    
2951
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2952
{
2953
    HTTPContext *rtp_c;
2954

    
2955
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2956
    if (!rtp_c) {
2957
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2958
        return;
2959
    }
2960

    
2961
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2962
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2963
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2964
        return;
2965
    }
2966

    
2967
    rtp_c->state = HTTPSTATE_READY;
2968
    rtp_c->first_pts = AV_NOPTS_VALUE;
2969
    /* now everything is OK, so we can send the connection parameters */
2970
    rtsp_reply_header(c, RTSP_STATUS_OK);
2971
    /* session ID */
2972
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2973
    url_fprintf(c->pb, "\r\n");
2974
}
2975

    
2976
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2977
{
2978
    HTTPContext *rtp_c;
2979
    char session_id[32];
2980

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

    
2987
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2988

    
2989
    /* abort the session */
2990
    close_connection(rtp_c);
2991

    
2992
    /* now everything is OK, so we can send the connection parameters */
2993
    rtsp_reply_header(c, RTSP_STATUS_OK);
2994
    /* session ID */
2995
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
2996
    url_fprintf(c->pb, "\r\n");
2997
}
2998

    
2999

    
3000
/********************************************************************/
3001
/* RTP handling */
3002

    
3003
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3004
                                       FFStream *stream, const char *session_id,
3005
                                       enum RTSPProtocol rtp_protocol)
3006
{
3007
    HTTPContext *c = NULL;
3008
    const char *proto_str;
3009

    
3010
    /* XXX: should output a warning page when coming
3011
       close to the connection limit */
3012
    if (nb_connections >= nb_max_connections)
3013
        goto fail;
3014

    
3015
    /* add a new connection */
3016
    c = av_mallocz(sizeof(HTTPContext));
3017
    if (!c)
3018
        goto fail;
3019

    
3020
    c->fd = -1;
3021
    c->poll_entry = NULL;
3022
    c->from_addr = *from_addr;
3023
    c->buffer_size = IOBUFFER_INIT_SIZE;
3024
    c->buffer = av_malloc(c->buffer_size);
3025
    if (!c->buffer)
3026
        goto fail;
3027
    nb_connections++;
3028
    c->stream = stream;
3029
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3030
    c->state = HTTPSTATE_READY;
3031
    c->is_packetized = 1;
3032
    c->rtp_protocol = rtp_protocol;
3033

    
3034
    /* protocol is shown in statistics */
3035
    switch(c->rtp_protocol) {
3036
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3037
        proto_str = "MCAST";
3038
        break;
3039
    case RTSP_PROTOCOL_RTP_UDP:
3040
        proto_str = "UDP";
3041
        break;
3042
    case RTSP_PROTOCOL_RTP_TCP:
3043
        proto_str = "TCP";
3044
        break;
3045
    default:
3046
        proto_str = "???";
3047
        break;
3048
    }
3049
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3050
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3051

    
3052
    current_bandwidth += stream->bandwidth;
3053

    
3054
    c->next = first_http_ctx;
3055
    first_http_ctx = c;
3056
    return c;
3057

    
3058
 fail:
3059
    if (c) {
3060
        av_free(c->buffer);
3061
        av_free(c);
3062
    }
3063
    return NULL;
3064
}
3065

    
3066
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3067
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3068
   used. */
3069
static int rtp_new_av_stream(HTTPContext *c,
3070
                             int stream_index, struct sockaddr_in *dest_addr,
3071
                             HTTPContext *rtsp_c)
3072
{
3073
    AVFormatContext *ctx;
3074
    AVStream *st;
3075
    char *ipaddr;
3076
    URLContext *h = NULL;
3077
    uint8_t *dummy_buf;
3078
    char buf2[32];
3079
    int max_packet_size;
3080

    
3081
    /* now we can open the relevant output stream */
3082
    ctx = av_alloc_format_context();
3083
    if (!ctx)
3084
        return -1;
3085
    ctx->oformat = guess_format("rtp", NULL, NULL);
3086

    
3087
    st = av_mallocz(sizeof(AVStream));
3088
    if (!st)
3089
        goto fail;
3090
    st->codec= avcodec_alloc_context();
3091
    ctx->nb_streams = 1;
3092
    ctx->streams[0] = st;
3093

    
3094
    if (!c->stream->feed ||
3095
        c->stream->feed == c->stream)
3096
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3097
    else
3098
        memcpy(st,
3099
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3100
               sizeof(AVStream));
3101
    st->priv_data = NULL;
3102

    
3103
    /* build destination RTP address */
3104
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3105

    
3106
    switch(c->rtp_protocol) {
3107
    case RTSP_PROTOCOL_RTP_UDP:
3108
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3109
        /* RTP/UDP case */
3110

    
3111
        /* XXX: also pass as parameter to function ? */
3112
        if (c->stream->is_multicast) {
3113
            int ttl;
3114
            ttl = c->stream->multicast_ttl;
3115
            if (!ttl)
3116
                ttl = 16;
3117
            snprintf(ctx->filename, sizeof(ctx->filename),
3118
                     "rtp://%s:%d?multicast=1&ttl=%d",
3119
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3120
        } else {
3121
            snprintf(ctx->filename, sizeof(ctx->filename),
3122
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3123
        }
3124

    
3125
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3126
            goto fail;
3127
        c->rtp_handles[stream_index] = h;
3128
        max_packet_size = url_get_max_packet_size(h);
3129
        break;
3130
    case RTSP_PROTOCOL_RTP_TCP:
3131
        /* RTP/TCP case */
3132
        c->rtsp_c = rtsp_c;
3133
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3134
        break;
3135
    default:
3136
        goto fail;
3137
    }
3138

    
3139
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3140
             ipaddr, ntohs(dest_addr->sin_port),
3141
             ctime1(buf2),
3142
             c->stream->filename, stream_index, c->protocol);
3143

    
3144
    /* normally, no packets should be output here, but the packet size may be checked */
3145
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3146
        /* XXX: close stream */
3147
        goto fail;
3148
    }
3149
    av_set_parameters(ctx, NULL);
3150
    if (av_write_header(ctx) < 0) {
3151
    fail:
3152
        if (h)
3153
            url_close(h);
3154
        av_free(ctx);
3155
        return -1;
3156
    }
3157
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3158
    av_free(dummy_buf);
3159

    
3160
    c->rtp_ctx[stream_index] = ctx;
3161
    return 0;
3162
}
3163

    
3164
/********************************************************************/
3165
/* ffserver initialization */
3166

    
3167
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3168
{
3169
    AVStream *fst;
3170

    
3171
    fst = av_mallocz(sizeof(AVStream));
3172
    if (!fst)
3173
        return NULL;
3174
    fst->codec= avcodec_alloc_context();
3175
    fst->priv_data = av_mallocz(sizeof(FeedData));
3176
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3177
    fst->index = stream->nb_streams;
3178
    av_set_pts_info(fst, 33, 1, 90000);
3179
    stream->streams[stream->nb_streams++] = fst;
3180
    return fst;
3181
}
3182

    
3183
/* return the stream number in the feed */
3184
static int add_av_stream(FFStream *feed, AVStream *st)
3185
{
3186
    AVStream *fst;
3187
    AVCodecContext *av, *av1;
3188
    int i;
3189

    
3190
    av = st->codec;
3191
    for(i=0;i<feed->nb_streams;i++) {
3192
        st = feed->streams[i];
3193
        av1 = st->codec;
3194
        if (av1->codec_id == av->codec_id &&
3195
            av1->codec_type == av->codec_type &&
3196
            av1->bit_rate == av->bit_rate) {
3197

    
3198
            switch(av->codec_type) {
3199
            case CODEC_TYPE_AUDIO:
3200
                if (av1->channels == av->channels &&
3201
                    av1->sample_rate == av->sample_rate)
3202
                    goto found;
3203
                break;
3204
            case CODEC_TYPE_VIDEO:
3205
                if (av1->width == av->width &&
3206
                    av1->height == av->height &&
3207
                    av1->time_base.den == av->time_base.den &&
3208
                    av1->time_base.num == av->time_base.num &&
3209
                    av1->gop_size == av->gop_size)
3210
                    goto found;
3211
                break;
3212
            default:
3213
                abort();
3214
            }
3215
        }
3216
    }
3217

    
3218
    fst = add_av_stream1(feed, av);
3219
    if (!fst)
3220
        return -1;
3221
    return feed->nb_streams - 1;
3222
 found:
3223
    return i;
3224
}
3225

    
3226
static void remove_stream(FFStream *stream)
3227
{
3228
    FFStream **ps;
3229
    ps = &first_stream;
3230
    while (*ps != NULL) {
3231
        if (*ps == stream)
3232
            *ps = (*ps)->next;
3233
        else
3234
            ps = &(*ps)->next;
3235
    }
3236
}
3237

    
3238
/* specific mpeg4 handling : we extract the raw parameters */
3239
static void extract_mpeg4_header(AVFormatContext *infile)
3240
{
3241
    int mpeg4_count, i, size;
3242
    AVPacket pkt;
3243
    AVStream *st;
3244
    const uint8_t *p;
3245

    
3246
    mpeg4_count = 0;
3247
    for(i=0;i<infile->nb_streams;i++) {
3248
        st = infile->streams[i];
3249
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3250
            st->codec->extradata_size == 0) {
3251
            mpeg4_count++;
3252
        }
3253
    }
3254
    if (!mpeg4_count)
3255
        return;
3256

    
3257
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3258
    while (mpeg4_count > 0) {
3259
        if (av_read_packet(infile, &pkt) < 0)
3260
            break;
3261
        st = infile->streams[pkt.stream_index];
3262
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3263
            st->codec->extradata_size == 0) {
3264
            av_freep(&st->codec->extradata);
3265
            /* fill extradata with the header */
3266
            /* XXX: we make hard suppositions here ! */
3267
            p = pkt.data;
3268
            while (p < pkt.data + pkt.size - 4) {
3269
                /* stop when vop header is found */
3270
                if (p[0] == 0x00 && p[1] == 0x00 &&
3271
                    p[2] == 0x01 && p[3] == 0xb6) {
3272
                    size = p - pkt.data;
3273
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3274
                    st->codec->extradata = av_malloc(size);
3275
                    st->codec->extradata_size = size;
3276
                    memcpy(st->codec->extradata, pkt.data, size);
3277
                    break;
3278
                }
3279
                p++;
3280
            }
3281
            mpeg4_count--;
3282
        }
3283
        av_free_packet(&pkt);
3284
    }
3285
}
3286

    
3287
/* compute the needed AVStream for each file */
3288
static void build_file_streams(void)
3289
{
3290
    FFStream *stream, *stream_next;
3291
    AVFormatContext *infile;
3292
    int i, ret;
3293

    
3294
    /* gather all streams */
3295
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3296
        stream_next = stream->next;
3297
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3298
            !stream->feed) {
3299
            /* the stream comes from a file */
3300
            /* try to open the file */
3301
            /* open stream */
3302
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3303
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3304
                /* specific case : if transport stream output to RTP,
3305
                   we use a raw transport stream reader */
3306
                stream->ap_in->mpeg2ts_raw = 1;
3307
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3308
            }
3309

    
3310
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3311
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3312
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3313
                /* remove stream (no need to spend more time on it) */
3314
            fail:
3315
                remove_stream(stream);
3316
            } else {
3317
                /* find all the AVStreams inside and reference them in
3318
                   'stream' */
3319
                if (av_find_stream_info(infile) < 0) {
3320
                    http_log("Could not find codec parameters from '%s'",
3321
                             stream->feed_filename);
3322
                    av_close_input_file(infile);
3323
                    goto fail;
3324
                }
3325
                extract_mpeg4_header(infile);
3326

    
3327
                for(i=0;i<infile->nb_streams;i++)
3328
                    add_av_stream1(stream, infile->streams[i]->codec);
3329

    
3330
                av_close_input_file(infile);
3331
            }
3332
        }
3333
    }
3334
}
3335

    
3336
/* compute the needed AVStream for each feed */
3337
static void build_feed_streams(void)
3338
{
3339
    FFStream *stream, *feed;
3340
    int i;
3341

    
3342
    /* gather all streams */
3343
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3344
        feed = stream->feed;
3345
        if (feed) {
3346
            if (!stream->is_feed) {
3347
                /* we handle a stream coming from a feed */
3348
                for(i=0;i<stream->nb_streams;i++)
3349
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3350
            }
3351
        }
3352
    }
3353

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

    
3365
    /* create feed files if needed */
3366
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3367
        int fd;
3368

    
3369
        if (url_exist(feed->feed_filename)) {
3370
            /* See if it matches */
3371
            AVFormatContext *s;
3372
            int matches = 0;
3373

    
3374
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3375
                /* Now see if it matches */
3376
                if (s->nb_streams == feed->nb_streams) {
3377
                    matches = 1;
3378
                    for(i=0;i<s->nb_streams;i++) {
3379
                        AVStream *sf, *ss;
3380
                        sf = feed->streams[i];
3381
                        ss = s->streams[i];
3382

    
3383
                        if (sf->index != ss->index ||
3384
                            sf->id != ss->id) {
3385
                            printf("Index & Id do not match for stream %d (%s)\n",
3386
                                   i, feed->feed_filename);
3387
                            matches = 0;
3388
                        } else {
3389
                            AVCodecContext *ccf, *ccs;
3390

    
3391
                            ccf = sf->codec;
3392
                            ccs = ss->codec;
3393
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3394

    
3395
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3396
                                printf("Codecs do not match for stream %d\n", i);
3397
                                matches = 0;
3398
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3399
                                printf("Codec bitrates do not match for stream %d\n", i);
3400
                                matches = 0;
3401
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3402
                                if (CHECK_CODEC(time_base.den) ||
3403
                                    CHECK_CODEC(time_base.num) ||
3404
                                    CHECK_CODEC(width) ||
3405
                                    CHECK_CODEC(height)) {
3406
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3407
                                    matches = 0;
3408
                                }
3409
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3410
                                if (CHECK_CODEC(sample_rate) ||
3411
                                    CHECK_CODEC(channels) ||
3412
                                    CHECK_CODEC(frame_size)) {
3413
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3414
                                    matches = 0;
3415
                                }
3416
                            } else {
3417
                                printf("Unknown codec type\n");
3418
                                matches = 0;
3419
                            }
3420
                        }
3421
                        if (!matches)
3422
                            break;
3423
                    }
3424
                } else
3425
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3426
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3427

    
3428
                av_close_input_file(s);
3429
            } else
3430
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3431
                        feed->feed_filename);
3432

    
3433
            if (!matches) {
3434
                if (feed->readonly) {
3435
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3436
                        feed->feed_filename);
3437
                    exit(1);
3438
                }
3439
                unlink(feed->feed_filename);
3440
            }
3441
        }
3442
        if (!url_exist(feed->feed_filename)) {
3443
            AVFormatContext s1, *s = &s1;
3444

    
3445
            if (feed->readonly) {
3446
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3447
                    feed->feed_filename);
3448
                exit(1);
3449
            }
3450

    
3451
            /* only write the header of the ffm file */
3452
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3453
                fprintf(stderr, "Could not open output feed file '%s'\n",
3454
                        feed->feed_filename);
3455
                exit(1);
3456
            }
3457
            s->oformat = feed->fmt;
3458
            s->nb_streams = feed->nb_streams;
3459
            for(i=0;i<s->nb_streams;i++) {
3460
                AVStream *st;
3461
                st = feed->streams[i];
3462
                s->streams[i] = st;
3463
            }
3464
            av_set_parameters(s, NULL);
3465
            if (av_write_header(s) < 0) {
3466
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3467
                exit(1);
3468
            }
3469
            /* XXX: need better api */
3470
            av_freep(&s->priv_data);
3471
            url_fclose(s->pb);
3472
        }
3473
        /* get feed size and write index */
3474
        fd = open(feed->feed_filename, O_RDONLY);
3475
        if (fd < 0) {
3476
            fprintf(stderr, "Could not open output feed file '%s'\n",
3477
                    feed->feed_filename);
3478
            exit(1);
3479
        }
3480

    
3481
        feed->feed_write_index = ffm_read_write_index(fd);
3482
        feed->feed_size = lseek(fd, 0, SEEK_END);
3483
        /* ensure that we do not wrap before the end of file */
3484
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3485
            feed->feed_max_size = feed->feed_size;
3486

    
3487
        close(fd);
3488
    }
3489
}
3490

    
3491
/* compute the bandwidth used by each stream */
3492
static void compute_bandwidth(void)
3493
{
3494
    int bandwidth, i;
3495
    FFStream *stream;
3496

    
3497
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3498
        bandwidth = 0;
3499
        for(i=0;i<stream->nb_streams;i++) {
3500
            AVStream *st = stream->streams[i];
3501
            switch(st->codec->codec_type) {
3502
            case CODEC_TYPE_AUDIO:
3503
            case CODEC_TYPE_VIDEO:
3504
                bandwidth += st->codec->bit_rate;
3505
                break;
3506
            default:
3507
                break;
3508
            }
3509
        }
3510
        stream->bandwidth = (bandwidth + 999) / 1000;
3511
    }
3512
}
3513

    
3514
static void get_arg(char *buf, int buf_size, const char **pp)
3515
{
3516
    const char *p;
3517
    char *q;
3518
    int quote;
3519

    
3520
    p = *pp;
3521
    while (isspace(*p)) p++;
3522
    q = buf;
3523
    quote = 0;
3524
    if (*p == '\"' || *p == '\'')
3525
        quote = *p++;
3526
    for(;;) {
3527
        if (quote) {
3528
            if (*p == quote)
3529
                break;
3530
        } else {
3531
            if (isspace(*p))
3532
                break;
3533
        }
3534
        if (*p == '\0')
3535
            break;
3536
        if ((q - buf) < buf_size - 1)
3537
            *q++ = *p;
3538
        p++;
3539
    }
3540
    *q = '\0';
3541
    if (quote && *p == quote)
3542
        p++;
3543
    *pp = p;
3544
}
3545

    
3546
/* add a codec and set the default parameters */
3547
static void add_codec(FFStream *stream, AVCodecContext *av)
3548
{
3549
    AVStream *st;
3550

    
3551
    /* compute default parameters */
3552
    switch(av->codec_type) {
3553
    case CODEC_TYPE_AUDIO:
3554
        if (av->bit_rate == 0)
3555
            av->bit_rate = 64000;
3556
        if (av->sample_rate == 0)
3557
            av->sample_rate = 22050;
3558
        if (av->channels == 0)
3559
            av->channels = 1;
3560
        break;
3561
    case CODEC_TYPE_VIDEO:
3562
        if (av->bit_rate == 0)
3563
            av->bit_rate = 64000;
3564
        if (av->time_base.num == 0){
3565
            av->time_base.den = 5;
3566
            av->time_base.num = 1;
3567
        }
3568
        if (av->width == 0 || av->height == 0) {
3569
            av->width = 160;
3570
            av->height = 128;
3571
        }
3572
        /* Bitrate tolerance is less for streaming */
3573
        if (av->bit_rate_tolerance == 0)
3574
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3575
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3576
        if (av->qmin == 0)
3577
            av->qmin = 3;
3578
        if (av->qmax == 0)
3579
            av->qmax = 31;
3580
        if (av->max_qdiff == 0)
3581
            av->max_qdiff = 3;
3582
        av->qcompress = 0.5;
3583
        av->qblur = 0.5;
3584

    
3585
        if (!av->nsse_weight)
3586
            av->nsse_weight = 8;
3587

    
3588
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3589
        av->me_method = ME_EPZS;
3590
        av->rc_buffer_aggressivity = 1.0;
3591

    
3592
        if (!av->rc_eq)
3593
            av->rc_eq = "tex^qComp";
3594
        if (!av->i_quant_factor)
3595
            av->i_quant_factor = -0.8;
3596
        if (!av->b_quant_factor)
3597
            av->b_quant_factor = 1.25;
3598
        if (!av->b_quant_offset)
3599
            av->b_quant_offset = 1.25;
3600
        if (!av->rc_max_rate)
3601
            av->rc_max_rate = av->bit_rate * 2;
3602

    
3603
        if (av->rc_max_rate && !av->rc_buffer_size) {
3604
            av->rc_buffer_size = av->rc_max_rate;
3605
        }
3606

    
3607

    
3608
        break;
3609
    default:
3610
        abort();
3611
    }
3612

    
3613
    st = av_mallocz(sizeof(AVStream));
3614
    if (!st)
3615
        return;
3616
    st->codec = avcodec_alloc_context();
3617
    stream->streams[stream->nb_streams++] = st;
3618
    memcpy(st->codec, av, sizeof(AVCodecContext));
3619
}
3620

    
3621
static int opt_audio_codec(const char *arg)
3622
{
3623
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3624

    
3625
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3626
        return CODEC_ID_NONE;
3627

    
3628
    return p->id;
3629
}
3630

    
3631
static int opt_video_codec(const char *arg)
3632
{
3633
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3634

    
3635
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3636
        return CODEC_ID_NONE;
3637

    
3638
    return p->id;
3639
}
3640

    
3641
/* simplistic plugin support */
3642

    
3643
#ifdef HAVE_DLOPEN
3644
static void load_module(const char *filename)
3645
{
3646
    void *dll;
3647
    void (*init_func)(void);
3648
    dll = dlopen(filename, RTLD_NOW);
3649
    if (!dll) {
3650
        fprintf(stderr, "Could not load module '%s' - %s\n",
3651
                filename, dlerror());
3652
        return;
3653
    }
3654

    
3655
    init_func = dlsym(dll, "ffserver_module_init");
3656
    if (!init_func) {
3657
        fprintf(stderr,
3658
                "%s: init function 'ffserver_module_init()' not found\n",
3659
                filename);
3660
        dlclose(dll);
3661
    }
3662

    
3663
    init_func();
3664
}
3665
#endif
3666

    
3667
static int parse_ffconfig(const char *filename)
3668
{
3669
    FILE *f;
3670
    char line[1024];
3671
    char cmd[64];
3672
    char arg[1024];
3673
    const char *p;
3674
    int val, errors, line_num;
3675
    FFStream **last_stream, *stream, *redirect;
3676
    FFStream **last_feed, *feed;
3677
    AVCodecContext audio_enc, video_enc;
3678
    int audio_id, video_id;
3679

    
3680
    f = fopen(filename, "r");
3681
    if (!f) {
3682
        perror(filename);
3683
        return -1;
3684
    }
3685

    
3686
    errors = 0;
3687
    line_num = 0;
3688
    first_stream = NULL;
3689
    last_stream = &first_stream;
3690
    first_feed = NULL;
3691
    last_feed = &first_feed;
3692
    stream = NULL;
3693
    feed = NULL;
3694
    redirect = NULL;
3695
    audio_id = CODEC_ID_NONE;
3696
    video_id = CODEC_ID_NONE;
3697
    for(;;) {
3698
        if (fgets(line, sizeof(line), f) == NULL)
3699
            break;
3700
        line_num++;
3701
        p = line;
3702
        while (isspace(*p))
3703
            p++;
3704
        if (*p == '\0' || *p == '#')
3705
            continue;
3706

    
3707
        get_arg(cmd, sizeof(cmd), &p);
3708

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

    
3780
                get_arg(feed->filename, sizeof(feed->filename), &p);
3781
                q = strrchr(feed->filename, '>');
3782
                if (*q)
3783
                    *q = '\0';
3784
                feed->fmt = guess_format("ffm", NULL, NULL);
3785
                /* defaut feed file */
3786
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3787
                         "/tmp/%s.ffm", feed->filename);
3788
                feed->feed_max_size = 5 * 1024 * 1024;
3789
                feed->is_feed = 1;
3790
                feed->feed = feed; /* self feeding :-) */
3791
            }
3792
        } else if (!strcasecmp(cmd, "Launch")) {
3793
            if (feed) {
3794
                int i;
3795

    
3796
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3797

    
3798
                for (i = 0; i < 62; i++) {
3799
                    get_arg(arg, sizeof(arg), &p);
3800
                    if (!arg[0])
3801
                        break;
3802

    
3803
                    feed->child_argv[i] = av_strdup(arg);
3804
                }
3805

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

    
3808
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3809
                    "http://%s:%d/%s",
3810
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3811
                    inet_ntoa(my_http_addr.sin_addr),
3812
                    ntohs(my_http_addr.sin_port), feed->filename);
3813

    
3814
                if (ffserver_debug)
3815
                {
3816
                    int j;
3817
                    fprintf(stdout, "Launch commandline: ");
3818
                    for (j = 0; j <= i; j++)
3819
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3820
                    fprintf(stdout, "\n");
3821
                }
3822
            }
3823
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3824
            if (feed) {
3825
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3826
                feed->readonly = 1;
3827
            } else if (stream) {
3828
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3829
            }
3830
        } else if (!strcasecmp(cmd, "File")) {
3831
            if (feed) {
3832
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3833
            } else if (stream)
3834
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3835
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3836
            if (feed) {
3837
                char *p1;
3838
                double fsize;
3839

    
3840
                get_arg(arg, sizeof(arg), &p);
3841
                p1 = arg;
3842
                fsize = strtod(p1, &p1);
3843
                switch(toupper(*p1)) {
3844
                case 'K':
3845
                    fsize *= 1024;
3846
                    break;
3847
                case 'M':
3848
                    fsize *= 1024 * 1024;
3849
                    break;
3850
                case 'G':
3851
                    fsize *= 1024 * 1024 * 1024;
3852
                    break;
3853
                }
3854
                feed->feed_max_size = (int64_t)fsize;
3855
            }
3856
        } else if (!strcasecmp(cmd, "</Feed>")) {
3857
            if (!feed) {
3858
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3859
                        filename, line_num);
3860
                errors++;
3861
            }
3862
            feed = NULL;
3863
        } else if (!strcasecmp(cmd, "<Stream")) {
3864
            /*********************************************/
3865
            /* Stream related options */
3866
            char *q;
3867
            if (stream || feed) {
3868
                fprintf(stderr, "%s:%d: Already in a tag\n",
3869
                        filename, line_num);
3870
            } else {
3871
                stream = av_mallocz(sizeof(FFStream));
3872
                *last_stream = stream;
3873
                last_stream = &stream->next;
3874

    
3875
                get_arg(stream->filename, sizeof(stream->filename), &p);
3876
                q = strrchr(stream->filename, '>');
3877
                if (*q)
3878
                    *q = '\0';
3879
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3880
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3881
                memset(&video_enc, 0, sizeof(AVCodecContext));
3882
                audio_id = CODEC_ID_NONE;
3883
                video_id = CODEC_ID_NONE;
3884
                if (stream->fmt) {
3885
                    audio_id = stream->fmt->audio_codec;
3886
                    video_id = stream->fmt->video_codec;
3887
                }
3888
            }
3889
        } else if (!strcasecmp(cmd, "Feed")) {
3890
            get_arg(arg, sizeof(arg), &p);
3891
            if (stream) {
3892
                FFStream *sfeed;
3893

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

    
4004
                get_arg(arg, sizeof(arg), &p);
4005

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

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

    
4161
            get_arg(arg, sizeof(arg), &p);
4162

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

    
4170
            get_arg(arg, sizeof(arg), &p);
4171

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

    
4180
            if (!errors) {
4181
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4182
                IPAddressACL **naclp = 0;
4183

    
4184
                acl.next = 0;
4185
                *nacl = acl;
4186

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

    
4197
                if (naclp) {
4198
                    while (*naclp)
4199
                        naclp = &(*naclp)->next;
4200

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

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

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

    
4309
static void handle_child_exit(int sig)
4310
{
4311
    pid_t pid;
4312
    int status;
4313

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

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

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

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

    
4331
    need_to_start_children = 1;
4332
}
4333

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

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

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

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

    
4363
    av_register_all();
4364

    
4365
    show_banner();
4366

    
4367
    config_filename = "/etc/ffserver.conf";
4368

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

    
4373
    parse_options(argc, argv, options, NULL);
4374

    
4375
    putenv("http_proxy");               /* Kill the http_proxy */
4376

    
4377
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4378

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

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

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

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

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

    
4404
    build_file_streams();
4405

    
4406
    build_feed_streams();
4407

    
4408
    compute_bandwidth();
4409

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

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

    
4436
    /* signal init */
4437
    signal(SIGPIPE, SIG_IGN);
4438

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

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

    
4452
    return 0;
4453
}