Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 86074ed1

History | View | Annotate | Download (148 KB)

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

    
22
#include "config.h"
23
#ifndef HAVE_CLOSESOCKET
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "avformat.h"
29

    
30
#include <stdarg.h>
31
#include <unistd.h>
32
#include <fcntl.h>
33
#include <sys/ioctl.h>
34
#ifdef HAVE_SYS_POLL_H
35
#include <sys/poll.h>
36
#endif
37
#include <errno.h>
38
#include <sys/time.h>
39
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
40
#include <time.h>
41
#include <sys/wait.h>
42
#include <signal.h>
43
#ifdef HAVE_DLFCN_H
44
#include <dlfcn.h>
45
#endif
46

    
47
#include "network.h"
48
#include "version.h"
49
#include "ffserver.h"
50
#include "random.h"
51
#include "avstring.h"
52
#include "cmdutils.h"
53

    
54
#undef exit
55

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

    
59
/* maximum number of simultaneous HTTP connections */
60
#define HTTP_MAX_CONNECTIONS 2000
61

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

    
72
    RTSPSTATE_WAIT_REQUEST,
73
    RTSPSTATE_SEND_REPLY,
74
    RTSPSTATE_SEND_PACKET,
75
};
76

    
77
const char *http_state[] = {
78
    "HTTP_WAIT_REQUEST",
79
    "HTTP_SEND_HEADER",
80

    
81
    "SEND_DATA_HEADER",
82
    "SEND_DATA",
83
    "SEND_DATA_TRAILER",
84
    "RECEIVE_DATA",
85
    "WAIT_FEED",
86
    "READY",
87

    
88
    "RTSP_WAIT_REQUEST",
89
    "RTSP_SEND_REPLY",
90
    "RTSP_SEND_PACKET",
91
};
92

    
93
#define IOBUFFER_INIT_SIZE 8192
94

    
95
/* timeouts are in ms */
96
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
97
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
98

    
99
#define SYNC_TIMEOUT (10 * 1000)
100

    
101
typedef struct {
102
    int64_t count1, count2;
103
    int64_t time1, time2;
104
} DataRateData;
105

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

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

    
156
    /* RTP state specific */
157
    enum RTSPProtocol rtp_protocol;
158
    char session_id[32]; /* session id */
159
    AVFormatContext *rtp_ctx[MAX_STREAMS];
160

    
161
    /* RTP/UDP specific */
162
    URLContext *rtp_handles[MAX_STREAMS];
163

    
164
    /* RTP/TCP specific */
165
    struct HTTPContext *rtsp_c;
166
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
167
} HTTPContext;
168

    
169
static AVFrame dummy_frame;
170

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
288
static int ffserver_debug;
289
static int ffserver_daemon;
290
static int no_launch;
291
static int need_to_start_children;
292

    
293
static int nb_max_connections;
294
static int nb_connections;
295

    
296
static int max_bandwidth;
297
static int current_bandwidth;
298

    
299
static int64_t cur_time;           // Making this global saves on passing it around everywhere
300

    
301
static AVRandomState random_state;
302

    
303
static FILE *logfile = NULL;
304

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

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

    
317
static char *ctime1(char *buf2)
318
{
319
    time_t ti;
320
    char *p;
321

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

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

    
335
    if (c->suppress_log)
336
        return;
337

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

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

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

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

    
366

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

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

    
376
            feed->pid = fork();
377

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

    
388
                for (i = 3; i < 256; i++)
389
                    close(i);
390

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

    
401
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
402

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

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

    
413
                signal(SIGPIPE, SIG_DFL);
414

    
415
                execvp(pathname, feed->child_argv);
416

    
417
                _exit(1);
418
            }
419
        }
420
    }
421
}
422

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

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

    
434
    tmp = 1;
435
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
436

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

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

    
452
    return server_fd;
453
}
454

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

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

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

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

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

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

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

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

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

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

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

    
525
    http_log("ffserver started.\n");
526

    
527
    start_children(first_feed);
528

    
529
    first_http_ctx = NULL;
530
    nb_connections = 0;
531

    
532
    start_multicast();
533

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

    
540
        poll_entry->fd = rtsp_server_fd;
541
        poll_entry->events = POLLIN;
542
        poll_entry++;
543

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

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

    
603
        cur_time = av_gettime() / 1000;
604

    
605
        if (need_to_start_children) {
606
            need_to_start_children = 0;
607
            start_children(first_feed);
608
        }
609

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

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

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

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

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

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

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

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

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

    
677
    c->next = first_http_ctx;
678
    first_http_ctx = c;
679
    nb_connections++;
680

    
681
    start_wait_request(c, is_rtsp);
682

    
683
    return;
684

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

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

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

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

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

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

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

    
746
    ctx = &c->fmt_ctx;
747

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

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

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

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

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

    
777
static int handle_connection(HTTPContext *c)
778
{
779
    int len, ret;
780

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

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

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

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

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

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

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

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

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

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

    
962
            while (*q && *q != '\n' && isspace(*q))
963
                q++;
964

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

    
969
                q += 20;
970

    
971
                memset(rates, 0xff, ratelen);
972

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

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

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

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

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

    
995
        p++;
996
    }
997

    
998
    return 0;
999
}
1000

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

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

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

    
1016
        /* Potential stream */
1017

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

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

    
1035
    return best;
1036
}
1037

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

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

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

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

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

    
1073
    return action_required;
1074
}
1075

    
1076

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1204
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1205

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

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

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

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

    
1230
        p++;
1231
    }
1232

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

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

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

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

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

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

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

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

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

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

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

    
1327
    if (redir_type != REDIR_NONE) {
1328
        char *hostinfo = 0;
1329

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

    
1339
            p++;
1340
        }
1341

    
1342
        if (hostinfo) {
1343
            char *eoh;
1344
            char hostbuf[260];
1345

    
1346
            while (isspace(*hostinfo))
1347
                hostinfo++;
1348

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

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

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

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

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

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

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

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

    
1447
    stream->conns_served++;
1448

    
1449
    /* XXX: add there authenticate and IP match */
1450

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

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

    
1471
                p++;
1472
            }
1473

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

    
1477
                logline += 17;
1478

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

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

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

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

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

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

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

    
1522
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1523
        goto send_stats;
1524

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

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

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

    
1543
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1544

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

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

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

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

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

    
1587
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1588
}
1589

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1752
                parameters[0] = 0;
1753

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

    
1772
        }
1773
        stream = stream->next;
1774
    }
1775

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1925
    /* open stream */
1926
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1927
                           buf_size, c->stream->ap_in) < 0) {
1928
        http_log("%s not found", input_filename);
1929
        return -1;
1930
    }
1931
    s->flags |= AVFMT_FLAG_GENPTS;
1932
    c->fmt_in = s;
1933
    av_find_stream_info(c->fmt_in);
1934

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

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

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

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

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

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

    
1982

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

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

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

    
2017
            *st = *src;
2018
            st->priv_data = 0;
2019
            st->codec->frame_number = 0; /* XXX: should be done in
2020
                                           AVStream, not in codec */
2021
            /* I'm pretty sure that this is not correct...
2022
             * However, without it, we crash
2023
             */
2024
            st->codec->coded_frame = &dummy_frame;
2025
        }
2026
        c->got_key_frame = 0;
2027

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

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

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

    
2043
        c->state = HTTPSTATE_SEND_DATA;
2044
        c->last_packet_sent = 0;
2045
        break;
2046
    case HTTPSTATE_SEND_DATA:
2047
        /* find a new packet */
2048
        {
2049
            AVPacket pkt;
2050

    
2051
            /* read a packet from the input stream */
2052
            if (c->stream->feed)
2053
                ffm_set_write_index(c->fmt_in,
2054
                                    c->stream->feed->feed_write_index,
2055
                                    c->stream->feed->feed_size);
2056

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2352
    /* open feed */
2353
    fd = open(c->stream->feed_filename, O_RDWR);
2354
    if (fd < 0)
2355
        return -1;
2356
    c->feed_fd = fd;
2357

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

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

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

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

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

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

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

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

    
2411
            feed->feed_write_index += FFM_PACKET_SIZE;
2412
            /* update file size */
2413
            if (feed->feed_write_index > c->stream->feed_size)
2414
                feed->feed_size = feed->feed_write_index;
2415

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

    
2420
            /* write index */
2421
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2422

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

    
2436
            memset(&s, 0, sizeof(s));
2437

    
2438
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2439
            pb->buf_end = c->buffer_end;        /* ?? */
2440
            pb->is_streamed = 1;
2441

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

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

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

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

    
2472
    return 0;
2473
 fail:
2474
    c->stream->feed_opened = 0;
2475
    close(c->feed_fd);
2476
    return -1;
2477
}
2478

    
2479
/********************************************************************/
2480
/* RTSP handling */
2481

    
2482
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2483
{
2484
    const char *str;
2485
    time_t ti;
2486
    char *p;
2487
    char buf2[32];
2488

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

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

    
2531
    /* output GMT time */
2532
    ti = time(NULL);
2533
    p = ctime(&ti);
2534
    strcpy(buf2, p);
2535
    p = buf2 + strlen(p) - 1;
2536
    if (*p == '\n')
2537
        *p = '\0';
2538
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2539
}
2540

    
2541
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2542
{
2543
    rtsp_reply_header(c, error_number);
2544
    url_fprintf(c->pb, "\r\n");
2545
}
2546

    
2547
static int rtsp_parse_request(HTTPContext *c)
2548
{
2549
    const char *p, *p1, *p2;
2550
    char cmd[32];
2551
    char url[1024];
2552
    char protocol[32];
2553
    char line[1024];
2554
    ByteIOContext pb1;
2555
    int len;
2556
    RTSPHeader header1, *header = &header1;
2557

    
2558
    c->buffer_ptr[0] = '\0';
2559
    p = c->buffer;
2560

    
2561
    get_word(cmd, sizeof(cmd), &p);
2562
    get_word(url, sizeof(url), &p);
2563
    get_word(protocol, sizeof(protocol), &p);
2564

    
2565
    av_strlcpy(c->method, cmd, sizeof(c->method));
2566
    av_strlcpy(c->url, url, sizeof(c->url));
2567
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2568

    
2569
    c->pb = &pb1;
2570
    if (url_open_dyn_buf(c->pb) < 0) {
2571
        /* XXX: cannot do more */
2572
        c->pb = NULL; /* safety */
2573
        return -1;
2574
    }
2575

    
2576
    /* check version name */
2577
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2578
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2579
        goto the_end;
2580
    }
2581

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

    
2608
    /* handle sequence number */
2609
    c->seq = header->seq;
2610

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

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

    
2639
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2640
                                   struct in_addr my_ip)
2641
{
2642
    AVFormatContext *avc;
2643
    AVStream avs[MAX_STREAMS];
2644
    int i;
2645

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

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

    
2670
    return strlen(*pbuffer);
2671
}
2672

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

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

    
2691
    /* find which url is asked */
2692
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2693
    path = path1;
2694
    if (*path == '/')
2695
        path++;
2696

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

    
2708
 found:
2709
    /* prepare the media description in sdp format */
2710

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

    
2726
static HTTPContext *find_rtp_session(const char *session_id)
2727
{
2728
    HTTPContext *c;
2729

    
2730
    if (session_id[0] == '\0')
2731
        return NULL;
2732

    
2733
    for(c = first_http_ctx; c != NULL; c = c->next) {
2734
        if (!strcmp(c->session_id, session_id))
2735
            return c;
2736
    }
2737
    return NULL;
2738
}
2739

    
2740
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2741
{
2742
    RTSPTransportField *th;
2743
    int i;
2744

    
2745
    for(i=0;i<h->nb_transports;i++) {
2746
        th = &h->transports[i];
2747
        if (th->protocol == protocol)
2748
            return th;
2749
    }
2750
    return NULL;
2751
}
2752

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

    
2766
    /* find which url is asked */
2767
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2768
    path = path1;
2769
    if (*path == '/')
2770
        path++;
2771

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

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

    
2800
    /* generate session id if needed */
2801
    if (h->session_id[0] == '\0')
2802
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2803
                 av_random(&random_state), av_random(&random_state));
2804

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

    
2818
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2819
                                   th->protocol);
2820
        if (!rtp_c) {
2821
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2822
            return;
2823
        }
2824

    
2825
        /* open input stream */
2826
        if (open_input_stream(rtp_c, "") < 0) {
2827
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2828
            return;
2829
        }
2830
    }
2831

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

    
2839
    /* test if stream is already set up */
2840
    if (rtp_c->rtp_ctx[stream_index]) {
2841
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2842
        return;
2843
    }
2844

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

    
2853
    /* setup default options */
2854
    setup.transport_option[0] = '\0';
2855
    dest_addr = rtp_c->from_addr;
2856
    dest_addr.sin_port = htons(th->client_port_min);
2857

    
2858
    /* setup stream */
2859
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2860
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2861
        return;
2862
    }
2863

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

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

    
2888

    
2889
    url_fprintf(c->pb, "\r\n");
2890
}
2891

    
2892

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

    
2904
    rtp_c = find_rtp_session(session_id);
2905
    if (!rtp_c)
2906
        return NULL;
2907

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

    
2925
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2926
{
2927
    HTTPContext *rtp_c;
2928

    
2929
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2930
    if (!rtp_c) {
2931
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2932
        return;
2933
    }
2934

    
2935
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2936
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2937
        rtp_c->state != HTTPSTATE_READY) {
2938
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2939
        return;
2940
    }
2941

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

    
2950
    rtp_c->state = HTTPSTATE_SEND_DATA;
2951

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

    
2959
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2960
{
2961
    HTTPContext *rtp_c;
2962

    
2963
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2964
    if (!rtp_c) {
2965
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2966
        return;
2967
    }
2968

    
2969
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2970
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2971
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2972
        return;
2973
    }
2974

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

    
2984
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2985
{
2986
    HTTPContext *rtp_c;
2987
    char session_id[32];
2988

    
2989
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2990
    if (!rtp_c) {
2991
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2992
        return;
2993
    }
2994

    
2995
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2996

    
2997
    /* abort the session */
2998
    close_connection(rtp_c);
2999

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

    
3007

    
3008
/********************************************************************/
3009
/* RTP handling */
3010

    
3011
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3012
                                       FFStream *stream, const char *session_id,
3013
                                       enum RTSPProtocol rtp_protocol)
3014
{
3015
    HTTPContext *c = NULL;
3016
    const char *proto_str;
3017

    
3018
    /* XXX: should output a warning page when coming
3019
       close to the connection limit */
3020
    if (nb_connections >= nb_max_connections)
3021
        goto fail;
3022

    
3023
    /* add a new connection */
3024
    c = av_mallocz(sizeof(HTTPContext));
3025
    if (!c)
3026
        goto fail;
3027

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

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

    
3060
    current_bandwidth += stream->bandwidth;
3061

    
3062
    c->next = first_http_ctx;
3063
    first_http_ctx = c;
3064
    return c;
3065

    
3066
 fail:
3067
    if (c) {
3068
        av_free(c->buffer);
3069
        av_free(c);
3070
    }
3071
    return NULL;
3072
}
3073

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

    
3089
    /* now we can open the relevant output stream */
3090
    ctx = av_alloc_format_context();
3091
    if (!ctx)
3092
        return -1;
3093
    ctx->oformat = guess_format("rtp", NULL, NULL);
3094

    
3095
    st = av_mallocz(sizeof(AVStream));
3096
    if (!st)
3097
        goto fail;
3098
    st->codec= avcodec_alloc_context();
3099
    ctx->nb_streams = 1;
3100
    ctx->streams[0] = st;
3101

    
3102
    if (!c->stream->feed ||
3103
        c->stream->feed == c->stream)
3104
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3105
    else
3106
        memcpy(st,
3107
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3108
               sizeof(AVStream));
3109
    st->priv_data = NULL;
3110

    
3111
    /* build destination RTP address */
3112
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3113

    
3114
    switch(c->rtp_protocol) {
3115
    case RTSP_PROTOCOL_RTP_UDP:
3116
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3117
        /* RTP/UDP case */
3118

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

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

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

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

    
3168
    c->rtp_ctx[stream_index] = ctx;
3169
    return 0;
3170
}
3171

    
3172
/********************************************************************/
3173
/* ffserver initialization */
3174

    
3175
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3176
{
3177
    AVStream *fst;
3178

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

    
3192
/* return the stream number in the feed */
3193
static int add_av_stream(FFStream *feed, AVStream *st)
3194
{
3195
    AVStream *fst;
3196
    AVCodecContext *av, *av1;
3197
    int i;
3198

    
3199
    av = st->codec;
3200
    for(i=0;i<feed->nb_streams;i++) {
3201
        st = feed->streams[i];
3202
        av1 = st->codec;
3203
        if (av1->codec_id == av->codec_id &&
3204
            av1->codec_type == av->codec_type &&
3205
            av1->bit_rate == av->bit_rate) {
3206

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

    
3227
    fst = add_av_stream1(feed, av);
3228
    if (!fst)
3229
        return -1;
3230
    return feed->nb_streams - 1;
3231
 found:
3232
    return i;
3233
}
3234

    
3235
static void remove_stream(FFStream *stream)
3236
{
3237
    FFStream **ps;
3238
    ps = &first_stream;
3239
    while (*ps != NULL) {
3240
        if (*ps == stream)
3241
            *ps = (*ps)->next;
3242
        else
3243
            ps = &(*ps)->next;
3244
    }
3245
}
3246

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

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

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

    
3296
/* compute the needed AVStream for each file */
3297
static void build_file_streams(void)
3298
{
3299
    FFStream *stream, *stream_next;
3300
    AVFormatContext *infile;
3301
    int i;
3302

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

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

    
3336
                for(i=0;i<infile->nb_streams;i++)
3337
                    add_av_stream1(stream, infile->streams[i]->codec);
3338

    
3339
                av_close_input_file(infile);
3340
            }
3341
        }
3342
    }
3343
}
3344

    
3345
/* compute the needed AVStream for each feed */
3346
static void build_feed_streams(void)
3347
{
3348
    FFStream *stream, *feed;
3349
    int i;
3350

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

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

    
3374
    /* create feed files if needed */
3375
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3376
        int fd;
3377

    
3378
        if (url_exist(feed->feed_filename)) {
3379
            /* See if it matches */
3380
            AVFormatContext *s;
3381
            int matches = 0;
3382

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

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

    
3400
                            ccf = sf->codec;
3401
                            ccs = ss->codec;
3402
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3403

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

    
3437
                av_close_input_file(s);
3438
            } else
3439
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3440
                        feed->feed_filename);
3441

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

    
3454
            if (feed->readonly) {
3455
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3456
                    feed->feed_filename);
3457
                exit(1);
3458
            }
3459

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

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

    
3496
        close(fd);
3497
    }
3498
}
3499

    
3500
/* compute the bandwidth used by each stream */
3501
static void compute_bandwidth(void)
3502
{
3503
    int bandwidth, i;
3504
    FFStream *stream;
3505

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

    
3523
static void get_arg(char *buf, int buf_size, const char **pp)
3524
{
3525
    const char *p;
3526
    char *q;
3527
    int quote;
3528

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

    
3555
/* add a codec and set the default parameters */
3556
static void add_codec(FFStream *stream, AVCodecContext *av)
3557
{
3558
    AVStream *st;
3559

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

    
3593
        if (!av->nsse_weight)
3594
            av->nsse_weight = 8;
3595

    
3596
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3597
        av->me_method = ME_EPZS;
3598
        av->rc_buffer_aggressivity = 1.0;
3599

    
3600
        if (!av->rc_eq)
3601
            av->rc_eq = "tex^qComp";
3602
        if (!av->i_quant_factor)
3603
            av->i_quant_factor = -0.8;
3604
        if (!av->b_quant_factor)
3605
            av->b_quant_factor = 1.25;
3606
        if (!av->b_quant_offset)
3607
            av->b_quant_offset = 1.25;
3608
        if (!av->rc_max_rate)
3609
            av->rc_max_rate = av->bit_rate * 2;
3610

    
3611
        if (av->rc_max_rate && !av->rc_buffer_size) {
3612
            av->rc_buffer_size = av->rc_max_rate;
3613
        }
3614

    
3615

    
3616
        break;
3617
    default:
3618
        abort();
3619
    }
3620

    
3621
    st = av_mallocz(sizeof(AVStream));
3622
    if (!st)
3623
        return;
3624
    st->codec = avcodec_alloc_context();
3625
    stream->streams[stream->nb_streams++] = st;
3626
    memcpy(st->codec, av, sizeof(AVCodecContext));
3627
}
3628

    
3629
static int opt_audio_codec(const char *arg)
3630
{
3631
    AVCodec *p;
3632

    
3633
    p = first_avcodec;
3634
    while (p) {
3635
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3636
            break;
3637
        p = p->next;
3638
    }
3639
    if (p == NULL)
3640
        return CODEC_ID_NONE;
3641

    
3642
    return p->id;
3643
}
3644

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

    
3649
    p = first_avcodec;
3650
    while (p) {
3651
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3652
            break;
3653
        p = p->next;
3654
    }
3655
    if (p == NULL)
3656
        return CODEC_ID_NONE;
3657

    
3658
    return p->id;
3659
}
3660

    
3661
/* simplistic plugin support */
3662

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

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

    
3683
    init_func();
3684
}
3685
#endif
3686

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

    
3700
    f = fopen(filename, "r");
3701
    if (!f) {
3702
        perror(filename);
3703
        return -1;
3704
    }
3705

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

    
3727
        get_arg(cmd, sizeof(cmd), &p);
3728

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

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

    
3816
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3817

    
3818
                for (i = 0; i < 62; i++) {
3819
                    get_arg(arg, sizeof(arg), &p);
3820
                    if (!arg[0])
3821
                        break;
3822

    
3823
                    feed->child_argv[i] = av_strdup(arg);
3824
                }
3825

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

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

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

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

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

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

    
4022
                get_arg(arg, sizeof(arg), &p);
4023

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

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

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

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

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

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

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

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

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

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

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

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

    
4312
    fclose(f);
4313
    if (errors)
4314
        return -1;
4315
    else
4316
        return 0;
4317
}
4318

    
4319
static void show_help(void)
4320
{
4321
    show_banner(program_name, program_birth_year);
4322
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4323
           "Hyper fast multi format Audio/Video streaming server\n"
4324
           "\n"
4325
           "-L            : print the LICENSE\n"
4326
           "-h            : this help\n"
4327
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4328
           );
4329
}
4330

    
4331
static void handle_child_exit(int sig)
4332
{
4333
    pid_t pid;
4334
    int status;
4335

    
4336
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4337
        FFStream *feed;
4338

    
4339
        for (feed = first_feed; feed; feed = feed->next) {
4340
            if (feed->pid == pid) {
4341
                int uptime = time(0) - feed->pid_start;
4342

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

    
4346
                if (uptime < 30)
4347
                    /* Turn off any more restarts */
4348
                    feed->child_argv = 0;
4349
            }
4350
        }
4351
    }
4352

    
4353
    need_to_start_children = 1;
4354
}
4355

    
4356
int main(int argc, char **argv)
4357
{
4358
    const char *config_filename;
4359
    int c;
4360
    struct sigaction sigact;
4361

    
4362
    av_register_all();
4363

    
4364
    config_filename = "/etc/ffserver.conf";
4365

    
4366
    my_program_name = argv[0];
4367
    my_program_dir = getcwd(0, 0);
4368
    ffserver_daemon = 1;
4369

    
4370
    for(;;) {
4371
        c = getopt(argc, argv, "ndLh?f:");
4372
        if (c == -1)
4373
            break;
4374
        switch(c) {
4375
        case 'L':
4376
            show_banner(program_name, program_birth_year);
4377
            show_license();
4378
            exit(0);
4379
        case '?':
4380
        case 'h':
4381
            show_help();
4382
            exit(0);
4383
        case 'n':
4384
            no_launch = 1;
4385
            break;
4386
        case 'd':
4387
            ffserver_debug = 1;
4388
            ffserver_daemon = 0;
4389
            break;
4390
        case 'f':
4391
            config_filename = optarg;
4392
            break;
4393
        default:
4394
            exit(2);
4395
        }
4396
    }
4397

    
4398
    putenv("http_proxy");               /* Kill the http_proxy */
4399

    
4400
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4401

    
4402
    /* address on which the server will handle HTTP connections */
4403
    my_http_addr.sin_family = AF_INET;
4404
    my_http_addr.sin_port = htons (8080);
4405
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4406

    
4407
    /* address on which the server will handle RTSP connections */
4408
    my_rtsp_addr.sin_family = AF_INET;
4409
    my_rtsp_addr.sin_port = htons (5454);
4410
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4411

    
4412
    nb_max_connections = 5;
4413
    max_bandwidth = 1000;
4414
    first_stream = NULL;
4415
    logfilename[0] = '\0';
4416

    
4417
    memset(&sigact, 0, sizeof(sigact));
4418
    sigact.sa_handler = handle_child_exit;
4419
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4420
    sigaction(SIGCHLD, &sigact, 0);
4421

    
4422
    if (parse_ffconfig(config_filename) < 0) {
4423
        fprintf(stderr, "Incorrect config file - exiting.\n");
4424
        exit(1);
4425
    }
4426

    
4427
    build_file_streams();
4428

    
4429
    build_feed_streams();
4430

    
4431
    compute_bandwidth();
4432

    
4433
    /* put the process in background and detach it from its TTY */
4434
    if (ffserver_daemon) {
4435
        int pid;
4436

    
4437
        pid = fork();
4438
        if (pid < 0) {
4439
            perror("fork");
4440
            exit(1);
4441
        } else if (pid > 0) {
4442
            /* parent : exit */
4443
            exit(0);
4444
        } else {
4445
            /* child */
4446
            setsid();
4447
            chdir("/");
4448
            close(0);
4449
            open("/dev/null", O_RDWR);
4450
            if (strcmp(logfilename, "-") != 0) {
4451
                close(1);
4452
                dup(0);
4453
            }
4454
            close(2);
4455
            dup(0);
4456
        }
4457
    }
4458

    
4459
    /* signal init */
4460
    signal(SIGPIPE, SIG_IGN);
4461

    
4462
    /* open log file if needed */
4463
    if (logfilename[0] != '\0') {
4464
        if (!strcmp(logfilename, "-"))
4465
            logfile = stdout;
4466
        else
4467
            logfile = fopen(logfilename, "w");
4468
    }
4469

    
4470
    if (http_server() < 0) {
4471
        fprintf(stderr, "Could not start server\n");
4472
        exit(1);
4473
    }
4474

    
4475
    return 0;
4476
}