Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 755bfeab

History | View | Annotate | Download (152 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 "avformat.h"
23

    
24
#include <stdarg.h>
25
#include <unistd.h>
26
#include <fcntl.h>
27
#include <sys/ioctl.h>
28
#ifdef HAVE_SYS_POLL_H
29
#include <sys/poll.h>
30
#endif
31
#include <errno.h>
32
#include <sys/time.h>
33
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
34
#include <time.h>
35
#include <sys/wait.h>
36
#include <signal.h>
37
#ifdef HAVE_DLFCN_H
38
#include <dlfcn.h>
39
#endif
40

    
41
#include "network.h"
42
#include "version.h"
43
#include "ffserver.h"
44
#include "random.h"
45

    
46
#undef exit
47

    
48
/* maximum number of simultaneous HTTP connections */
49
#define HTTP_MAX_CONNECTIONS 2000
50

    
51
enum HTTPState {
52
    HTTPSTATE_WAIT_REQUEST,
53
    HTTPSTATE_SEND_HEADER,
54
    HTTPSTATE_SEND_DATA_HEADER,
55
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
56
    HTTPSTATE_SEND_DATA_TRAILER,
57
    HTTPSTATE_RECEIVE_DATA,
58
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
59
    HTTPSTATE_READY,
60

    
61
    RTSPSTATE_WAIT_REQUEST,
62
    RTSPSTATE_SEND_REPLY,
63
    RTSPSTATE_SEND_PACKET,
64
};
65

    
66
const char *http_state[] = {
67
    "HTTP_WAIT_REQUEST",
68
    "HTTP_SEND_HEADER",
69

    
70
    "SEND_DATA_HEADER",
71
    "SEND_DATA",
72
    "SEND_DATA_TRAILER",
73
    "RECEIVE_DATA",
74
    "WAIT_FEED",
75
    "READY",
76

    
77
    "RTSP_WAIT_REQUEST",
78
    "RTSP_SEND_REPLY",
79
    "RTSP_SEND_PACKET",
80
};
81

    
82
#define IOBUFFER_INIT_SIZE 8192
83

    
84
/* timeouts are in ms */
85
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
86
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
87

    
88
#define SYNC_TIMEOUT (10 * 1000)
89

    
90
typedef struct {
91
    int64_t count1, count2;
92
    int64_t time1, time2;
93
} DataRateData;
94

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

    
140
    /* RTSP state specific */
141
    uint8_t *pb_buffer; /* XXX: use that in all the code */
142
    ByteIOContext *pb;
143
    int seq; /* RTSP sequence number */
144

    
145
    /* RTP state specific */
146
    enum RTSPProtocol rtp_protocol;
147
    char session_id[32]; /* session id */
148
    AVFormatContext *rtp_ctx[MAX_STREAMS];
149

    
150
    /* RTP/UDP specific */
151
    URLContext *rtp_handles[MAX_STREAMS];
152

    
153
    /* RTP/TCP specific */
154
    struct HTTPContext *rtsp_c;
155
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
156
} HTTPContext;
157

    
158
static AVFrame dummy_frame;
159

    
160
/* each generated stream is described here */
161
enum StreamType {
162
    STREAM_TYPE_LIVE,
163
    STREAM_TYPE_STATUS,
164
    STREAM_TYPE_REDIRECT,
165
};
166

    
167
enum IPAddressAction {
168
    IP_ALLOW = 1,
169
    IP_DENY,
170
};
171

    
172
typedef struct IPAddressACL {
173
    struct IPAddressACL *next;
174
    enum IPAddressAction action;
175
    /* These are in host order */
176
    struct in_addr first;
177
    struct in_addr last;
178
} IPAddressACL;
179

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

    
216
    /* feed specific */
217
    int feed_opened;     /* true if someone is writing to the feed */
218
    int is_feed;         /* true if it is a feed */
219
    int readonly;        /* True if writing is prohibited to the file */
220
    int conns_served;
221
    int64_t bytes_served;
222
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
223
    int64_t feed_write_index;   /* current write position in feed (it wraps round) */
224
    int64_t feed_size;          /* current size of feed */
225
    struct FFStream *next_feed;
226
} FFStream;
227

    
228
typedef struct FeedData {
229
    long long data_count;
230
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
231
} FeedData;
232

    
233
static struct sockaddr_in my_http_addr;
234
static struct sockaddr_in my_rtsp_addr;
235

    
236
static char logfilename[1024];
237
static HTTPContext *first_http_ctx;
238
static FFStream *first_feed;   /* contains only feeds */
239
static FFStream *first_stream; /* contains all streams, including feeds */
240

    
241
static void new_connection(int server_fd, int is_rtsp);
242
static void close_connection(HTTPContext *c);
243

    
244
/* HTTP handling */
245
static int handle_connection(HTTPContext *c);
246
static int http_parse_request(HTTPContext *c);
247
static int http_send_data(HTTPContext *c);
248
static void compute_stats(HTTPContext *c);
249
static int open_input_stream(HTTPContext *c, const char *info);
250
static int http_start_receive_data(HTTPContext *c);
251
static int http_receive_data(HTTPContext *c);
252

    
253
/* RTSP handling */
254
static int rtsp_parse_request(HTTPContext *c);
255
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
256
static void rtsp_cmd_options(HTTPContext *c, const char *url);
257
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
258
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
259
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
260
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
261

    
262
/* SDP handling */
263
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
264
                                   struct in_addr my_ip);
265

    
266
/* RTP handling */
267
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
268
                                       FFStream *stream, const char *session_id,
269
                                       enum RTSPProtocol rtp_protocol);
270
static int rtp_new_av_stream(HTTPContext *c,
271
                             int stream_index, struct sockaddr_in *dest_addr,
272
                             HTTPContext *rtsp_c);
273

    
274
static const char *my_program_name;
275
static const char *my_program_dir;
276

    
277
static int ffserver_debug;
278
static int ffserver_daemon;
279
static int no_launch;
280
static int need_to_start_children;
281

    
282
static int nb_max_connections;
283
static int nb_connections;
284

    
285
static int max_bandwidth;
286
static int current_bandwidth;
287

    
288
static int64_t cur_time;           // Making this global saves on passing it around everywhere
289

    
290
static AVRandomState random_state;
291

    
292
static FILE *logfile = NULL;
293

    
294
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
295
{
296
    va_list ap;
297
    va_start(ap, fmt);
298

    
299
    if (logfile) {
300
        vfprintf(logfile, fmt, ap);
301
        fflush(logfile);
302
    }
303
    va_end(ap);
304
}
305

    
306
static char *ctime1(char *buf2)
307
{
308
    time_t ti;
309
    char *p;
310

    
311
    ti = time(NULL);
312
    p = ctime(&ti);
313
    strcpy(buf2, p);
314
    p = buf2 + strlen(p) - 1;
315
    if (*p == '\n')
316
        *p = '\0';
317
    return buf2;
318
}
319

    
320
static void log_connection(HTTPContext *c)
321
{
322
    char buf2[32];
323

    
324
    if (c->suppress_log)
325
        return;
326

    
327
    http_log("%s - - [%s] \"%s %s %s\" %d %"PRId64"\n",
328
             inet_ntoa(c->from_addr.sin_addr),
329
             ctime1(buf2), c->method, c->url,
330
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
331
}
332

    
333
static void update_datarate(DataRateData *drd, int64_t count)
334
{
335
    if (!drd->time1 && !drd->count1) {
336
        drd->time1 = drd->time2 = cur_time;
337
        drd->count1 = drd->count2 = count;
338
    } else {
339
        if (cur_time - drd->time2 > 5000) {
340
            drd->time1 = drd->time2;
341
            drd->count1 = drd->count2;
342
            drd->time2 = cur_time;
343
            drd->count2 = count;
344
        }
345
    }
346
}
347

    
348
/* In bytes per second */
349
static int compute_datarate(DataRateData *drd, int64_t count)
350
{
351
    if (cur_time == drd->time1)
352
        return 0;
353

    
354
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
355
}
356

    
357

    
358
static void start_children(FFStream *feed)
359
{
360
    if (no_launch)
361
        return;
362

    
363
    for (; feed; feed = feed->next) {
364
        if (feed->child_argv && !feed->pid) {
365
            feed->pid_start = time(0);
366

    
367
            feed->pid = fork();
368

    
369
            if (feed->pid < 0) {
370
                fprintf(stderr, "Unable to create children\n");
371
                exit(1);
372
            }
373
            if (!feed->pid) {
374
                /* In child */
375
                char pathname[1024];
376
                char *slash;
377
                int i;
378

    
379
                for (i = 3; i < 256; i++) {
380
                    close(i);
381
                }
382

    
383
                if (!ffserver_debug) {
384
                    i = open("/dev/null", O_RDWR);
385
                    if (i)
386
                        dup2(i, 0);
387
                    dup2(i, 1);
388
                    dup2(i, 2);
389
                    if (i)
390
                        close(i);
391
                }
392

    
393
                pstrcpy(pathname, sizeof(pathname), my_program_name);
394

    
395
                slash = strrchr(pathname, '/');
396
                if (!slash) {
397
                    slash = pathname;
398
                } else {
399
                    slash++;
400
                }
401
                strcpy(slash, "ffmpeg");
402

    
403
                /* This is needed to make relative pathnames work */
404
                chdir(my_program_dir);
405

    
406
                signal(SIGPIPE, SIG_DFL);
407

    
408
                execvp(pathname, feed->child_argv);
409

    
410
                _exit(1);
411
            }
412
        }
413
    }
414
}
415

    
416
/* open a listening socket */
417
static int socket_open_listen(struct sockaddr_in *my_addr)
418
{
419
    int server_fd, tmp;
420

    
421
    server_fd = socket(AF_INET,SOCK_STREAM,0);
422
    if (server_fd < 0) {
423
        perror ("socket");
424
        return -1;
425
    }
426

    
427
    tmp = 1;
428
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
429

    
430
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
431
        char bindmsg[32];
432
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
433
        perror (bindmsg);
434
        closesocket(server_fd);
435
        return -1;
436
    }
437

    
438
    if (listen (server_fd, 5) < 0) {
439
        perror ("listen");
440
        closesocket(server_fd);
441
        return -1;
442
    }
443
    ff_socket_nonblock(server_fd, 1);
444

    
445
    return server_fd;
446
}
447

    
448
/* start all multicast streams */
449
static void start_multicast(void)
450
{
451
    FFStream *stream;
452
    char session_id[32];
453
    HTTPContext *rtp_c;
454
    struct sockaddr_in dest_addr;
455
    int default_port, stream_index;
456

    
457
    default_port = 6000;
458
    for(stream = first_stream; stream != NULL; stream = stream->next) {
459
        if (stream->is_multicast) {
460
            /* open the RTP connection */
461
            snprintf(session_id, sizeof(session_id), "%08x%08x",
462
                     av_random(&random_state), av_random(&random_state));
463

    
464
            /* choose a port if none given */
465
            if (stream->multicast_port == 0) {
466
                stream->multicast_port = default_port;
467
                default_port += 100;
468
            }
469

    
470
            dest_addr.sin_family = AF_INET;
471
            dest_addr.sin_addr = stream->multicast_ip;
472
            dest_addr.sin_port = htons(stream->multicast_port);
473

    
474
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
475
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
476
            if (!rtp_c) {
477
                continue;
478
            }
479
            if (open_input_stream(rtp_c, "") < 0) {
480
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
481
                        stream->filename);
482
                continue;
483
            }
484

    
485
            /* open each RTP stream */
486
            for(stream_index = 0; stream_index < stream->nb_streams;
487
                stream_index++) {
488
                dest_addr.sin_port = htons(stream->multicast_port +
489
                                           2 * stream_index);
490
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
491
                    fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n",
492
                            stream->filename, stream_index);
493
                    exit(1);
494
                }
495
            }
496

    
497
            /* change state to send data */
498
            rtp_c->state = HTTPSTATE_SEND_DATA;
499
        }
500
    }
501
}
502

    
503
/* main loop of the http server */
504
static int http_server(void)
505
{
506
    int server_fd, ret, rtsp_server_fd, delay, delay1;
507
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
508
    HTTPContext *c, *c_next;
509

    
510
    server_fd = socket_open_listen(&my_http_addr);
511
    if (server_fd < 0)
512
        return -1;
513

    
514
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
515
    if (rtsp_server_fd < 0)
516
        return -1;
517

    
518
    http_log("ffserver started.\n");
519

    
520
    start_children(first_feed);
521

    
522
    first_http_ctx = NULL;
523
    nb_connections = 0;
524

    
525
    start_multicast();
526

    
527
    for(;;) {
528
        poll_entry = poll_table;
529
        poll_entry->fd = server_fd;
530
        poll_entry->events = POLLIN;
531
        poll_entry++;
532

    
533
        poll_entry->fd = rtsp_server_fd;
534
        poll_entry->events = POLLIN;
535
        poll_entry++;
536

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

    
587
        /* wait for an event on one connection. We poll at least every
588
           second to handle timeouts */
589
        do {
590
            ret = poll(poll_table, poll_entry - poll_table, delay);
591
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
592
                ff_neterrno() != FF_NETERROR(EINTR))
593
                return -1;
594
        } while (ret < 0);
595

    
596
        cur_time = av_gettime() / 1000;
597

    
598
        if (need_to_start_children) {
599
            need_to_start_children = 0;
600
            start_children(first_feed);
601
        }
602

    
603
        /* now handle the events */
604
        for(c = first_http_ctx; c != NULL; c = c_next) {
605
            c_next = c->next;
606
            if (handle_connection(c) < 0) {
607
                /* close and free the connection */
608
                log_connection(c);
609
                close_connection(c);
610
            }
611
        }
612

    
613
        poll_entry = poll_table;
614
        /* new HTTP connection request ? */
615
        if (poll_entry->revents & POLLIN) {
616
            new_connection(server_fd, 0);
617
        }
618
        poll_entry++;
619
        /* new RTSP connection request ? */
620
        if (poll_entry->revents & POLLIN) {
621
            new_connection(rtsp_server_fd, 1);
622
        }
623
    }
624
}
625

    
626
/* start waiting for a new HTTP/RTSP request */
627
static void start_wait_request(HTTPContext *c, int is_rtsp)
628
{
629
    c->buffer_ptr = c->buffer;
630
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
631

    
632
    if (is_rtsp) {
633
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
634
        c->state = RTSPSTATE_WAIT_REQUEST;
635
    } else {
636
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
637
        c->state = HTTPSTATE_WAIT_REQUEST;
638
    }
639
}
640

    
641
static void new_connection(int server_fd, int is_rtsp)
642
{
643
    struct sockaddr_in from_addr;
644
    int fd, len;
645
    HTTPContext *c = NULL;
646

    
647
    len = sizeof(from_addr);
648
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
649
                &len);
650
    if (fd < 0)
651
        return;
652
    ff_socket_nonblock(fd, 1);
653

    
654
    /* XXX: should output a warning page when coming
655
       close to the connection limit */
656
    if (nb_connections >= nb_max_connections)
657
        goto fail;
658

    
659
    /* add a new connection */
660
    c = av_mallocz(sizeof(HTTPContext));
661
    if (!c)
662
        goto fail;
663

    
664
    c->fd = fd;
665
    c->poll_entry = NULL;
666
    c->from_addr = from_addr;
667
    c->buffer_size = IOBUFFER_INIT_SIZE;
668
    c->buffer = av_malloc(c->buffer_size);
669
    if (!c->buffer)
670
        goto fail;
671

    
672
    c->next = first_http_ctx;
673
    first_http_ctx = c;
674
    nb_connections++;
675

    
676
    start_wait_request(c, is_rtsp);
677

    
678
    return;
679

    
680
 fail:
681
    if (c) {
682
        av_free(c->buffer);
683
        av_free(c);
684
    }
685
    closesocket(fd);
686
}
687

    
688
static void close_connection(HTTPContext *c)
689
{
690
    HTTPContext **cp, *c1;
691
    int i, nb_streams;
692
    AVFormatContext *ctx;
693
    URLContext *h;
694
    AVStream *st;
695

    
696
    /* remove connection from list */
697
    cp = &first_http_ctx;
698
    while ((*cp) != NULL) {
699
        c1 = *cp;
700
        if (c1 == c) {
701
            *cp = c->next;
702
        } else {
703
            cp = &c1->next;
704
        }
705
    }
706

    
707
    /* remove references, if any (XXX: do it faster) */
708
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
709
        if (c1->rtsp_c == c)
710
            c1->rtsp_c = NULL;
711
    }
712

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

    
727
    /* free RTP output streams if any */
728
    nb_streams = 0;
729
    if (c->stream)
730
        nb_streams = c->stream->nb_streams;
731

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

    
744
    ctx = &c->fmt_ctx;
745

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

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

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

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

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

    
775
static int handle_connection(HTTPContext *c)
776
{
777
    int len, ret;
778

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

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

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

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

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

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

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

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

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

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

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

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

    
968
                q += 20;
969

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

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

    
976
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
977
                        break;
978
                    }
979
                    stream_no--;
980
                    if (stream_no < ratelen && stream_no >= 0) {
981
                        rates[stream_no] = rate_no;
982
                    }
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

    
1017
        /* Potential stream */
1018

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

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

    
1036
    return best;
1037
}
1038

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

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

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

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

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

    
1074
    return action_required;
1075
}
1076

    
1077

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1233
        p++;
1234
    }
1235

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

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

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

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

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

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

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

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

    
1308
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1309
        current_bandwidth += stream->bandwidth;
1310
    }
1311

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

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

    
1331
    if (redir_type != REDIR_NONE) {
1332
        char *hostinfo = 0;
1333

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

    
1343
            p++;
1344
        }
1345

    
1346
        if (hostinfo) {
1347
            char *eoh;
1348
            char hostbuf[260];
1349

    
1350
            while (isspace(*hostinfo))
1351
                hostinfo++;
1352

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

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

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

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

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

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

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

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

    
1451
    stream->conns_served++;
1452

    
1453
    /* XXX: add there authenticate and IP match */
1454

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

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

    
1476
                p++;
1477
            }
1478

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

    
1482
                logline += 17;
1483

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

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

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

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

    
1505
                if (wmpc) {
1506
                    if (modify_current_stream(wmpc, ratebuf)) {
1507
                        wmpc->switch_pending = 1;
1508
                    }
1509
                }
1510
            }
1511

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

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

    
1531
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1532
        goto send_stats;
1533

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

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

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

    
1552
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1553

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

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

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

    
1589
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1590
{
1591
    static const char *suffix = " kMGTP";
1592
    const char *s;
1593

    
1594
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1595
    }
1596

    
1597
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1598
}
1599

    
1600
static void compute_stats(HTTPContext *c)
1601
{
1602
    HTTPContext *c1;
1603
    FFStream *stream;
1604
    char *p;
1605
    time_t ti;
1606
    int i, len;
1607
    ByteIOContext pb1, *pb = &pb1;
1608

    
1609
    if (url_open_dyn_buf(pb) < 0) {
1610
        /* XXX: return an error ? */
1611
        c->buffer_ptr = c->buffer;
1612
        c->buffer_end = c->buffer;
1613
        return;
1614
    }
1615

    
1616
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1617
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1618
    url_fprintf(pb, "Pragma: no-cache\r\n");
1619
    url_fprintf(pb, "\r\n");
1620

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

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

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

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

    
1722
    stream = first_stream;
1723
    while (stream != NULL) {
1724
        if (stream->feed == stream) {
1725
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1726
            if (stream->pid) {
1727
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1728

    
1729
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1730
                {
1731
                    FILE *pid_stat;
1732
                    char ps_cmd[64];
1733

    
1734
                    /* This is somewhat linux specific I guess */
1735
                    snprintf(ps_cmd, sizeof(ps_cmd),
1736
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1737
                             stream->pid);
1738

    
1739
                    pid_stat = popen(ps_cmd, "r");
1740
                    if (pid_stat) {
1741
                        char cpuperc[10];
1742
                        char cpuused[64];
1743

    
1744
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1745
                                   cpuused) == 2) {
1746
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1747
                                         cpuperc, cpuused);
1748
                        }
1749
                        fclose(pid_stat);
1750
                    }
1751
                }
1752
#endif
1753

    
1754
                url_fprintf(pb, "<p>");
1755
            }
1756
            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");
1757

    
1758
            for (i = 0; i < stream->nb_streams; i++) {
1759
                AVStream *st = stream->streams[i];
1760
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1761
                const char *type = "unknown";
1762
                char parameters[64];
1763

    
1764
                parameters[0] = 0;
1765

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

    
1784
        }
1785
        stream = stream->next;
1786
    }
1787

    
1788
#if 0
1789
    {
1790
        float avg;
1791
        AVCodecContext *enc;
1792
        char buf[1024];
1793

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

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

    
1818
    /* connection status */
1819
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1820

    
1821
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1822
                 nb_connections, nb_max_connections);
1823

    
1824
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1825
                 current_bandwidth, max_bandwidth);
1826

    
1827
    url_fprintf(pb, "<TABLE>\n");
1828
    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");
1829
    c1 = first_http_ctx;
1830
    i = 0;
1831
    while (c1 != NULL) {
1832
        int bitrate;
1833
        int j;
1834

    
1835
        bitrate = 0;
1836
        if (c1->stream) {
1837
            for (j = 0; j < c1->stream->nb_streams; j++) {
1838
                if (!c1->stream->feed) {
1839
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1840
                } else {
1841
                    if (c1->feed_streams[j] >= 0) {
1842
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1843
                    }
1844
                }
1845
            }
1846
        }
1847

    
1848
        i++;
1849
        p = inet_ntoa(c1->from_addr.sin_addr);
1850
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1851
                    i,
1852
                    c1->stream ? c1->stream->filename : "",
1853
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1854
                    p,
1855
                    c1->protocol,
1856
                    http_state[c1->state]);
1857
        fmt_bytecount(pb, bitrate);
1858
        url_fprintf(pb, "<td align=right>");
1859
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1860
        url_fprintf(pb, "<td align=right>");
1861
        fmt_bytecount(pb, c1->data_count);
1862
        url_fprintf(pb, "\n");
1863
        c1 = c1->next;
1864
    }
1865
    url_fprintf(pb, "</TABLE>\n");
1866

    
1867
    /* date */
1868
    ti = time(NULL);
1869
    p = ctime(&ti);
1870
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1871
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1872

    
1873
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1874
    c->buffer_ptr = c->pb_buffer;
1875
    c->buffer_end = c->pb_buffer + len;
1876
}
1877

    
1878
/* check if the parser needs to be opened for stream i */
1879
static void open_parser(AVFormatContext *s, int i)
1880
{
1881
    AVStream *st = s->streams[i];
1882
    AVCodec *codec;
1883

    
1884
    if (!st->codec->codec) {
1885
        codec = avcodec_find_decoder(st->codec->codec_id);
1886
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1887
            st->codec->parse_only = 1;
1888
            if (avcodec_open(st->codec, codec) < 0) {
1889
                st->codec->parse_only = 0;
1890
            }
1891
        }
1892
    }
1893
}
1894

    
1895
static int open_input_stream(HTTPContext *c, const char *info)
1896
{
1897
    char buf[128];
1898
    char input_filename[1024];
1899
    AVFormatContext *s;
1900
    int buf_size, i;
1901
    int64_t stream_pos;
1902

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

    
1929
#if 0
1930
    { time_t when = stream_pos / 1000000;
1931
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1932
    }
1933
#endif
1934

    
1935
    /* open stream */
1936
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1937
                           buf_size, c->stream->ap_in) < 0) {
1938
        http_log("%s not found", input_filename);
1939
        return -1;
1940
    }
1941
    c->fmt_in = s;
1942

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

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

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

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

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

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

    
1991

    
1992
static int http_prepare_data(HTTPContext *c)
1993
{
1994
    int i, len, ret;
1995
    AVFormatContext *ctx;
1996

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

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

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

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

    
2044
        av_set_parameters(&c->fmt_ctx, NULL);
2045
        if (av_write_header(&c->fmt_ctx) < 0)
2046
            return -1;
2047

    
2048
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2049
        c->buffer_ptr = c->pb_buffer;
2050
        c->buffer_end = c->pb_buffer + len;
2051

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

    
2060
            /* read a packet from the input stream */
2061
            if (c->stream->feed) {
2062
                ffm_set_write_index(c->fmt_in,
2063
                                    c->stream->feed->feed_write_index,
2064
                                    c->stream->feed->feed_size);
2065
            }
2066

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

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

    
2172
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2173
                        if (c->is_packetized) {
2174
                            int max_packet_size;
2175
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2176
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2177
                            else
2178
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2179
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2180
                        } else {
2181
                            ret = url_open_dyn_buf(&ctx->pb);
2182
                        }
2183
                        if (ret < 0) {
2184
                            /* XXX: potential leak */
2185
                            return -1;
2186
                        }
2187
                        if (pkt.dts != AV_NOPTS_VALUE)
2188
                            pkt.dts = av_rescale_q(pkt.dts,
2189
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2190
                                ctx->streams[pkt.stream_index]->time_base);
2191
                        if (pkt.pts != AV_NOPTS_VALUE)
2192
                            pkt.pts = av_rescale_q(pkt.pts,
2193
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2194
                                ctx->streams[pkt.stream_index]->time_base);
2195
                        if (av_write_frame(ctx, &pkt)) {
2196
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2197
                        }
2198

    
2199
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2200
                        c->cur_frame_bytes = len;
2201
                        c->buffer_ptr = c->pb_buffer;
2202
                        c->buffer_end = c->pb_buffer + len;
2203

    
2204
                        codec->frame_number++;
2205
                        if (len == 0)
2206
                            goto redo;
2207
                    }
2208
                    av_free_packet(&pkt);
2209
                }
2210
            }
2211
        }
2212
        break;
2213
    default:
2214
    case HTTPSTATE_SEND_DATA_TRAILER:
2215
        /* last packet test ? */
2216
        if (c->last_packet_sent || c->is_packetized)
2217
            return -1;
2218
        ctx = &c->fmt_ctx;
2219
        /* prepare header */
2220
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2221
            /* XXX: potential leak */
2222
            return -1;
2223
        }
2224
        av_write_trailer(ctx);
2225
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2226
        c->buffer_ptr = c->pb_buffer;
2227
        c->buffer_end = c->pb_buffer + len;
2228

    
2229
        c->last_packet_sent = 1;
2230
        break;
2231
    }
2232
    return 0;
2233
}
2234

    
2235
/* should convert the format at the same time */
2236
/* send data starting at c->buffer_ptr to the output connection
2237
   (either UDP or TCP connection) */
2238
static int http_send_data(HTTPContext *c)
2239
{
2240
    int len, ret;
2241

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

    
2272
                c->data_count += len;
2273
                update_datarate(&c->datarate, c->data_count);
2274
                if (c->stream)
2275
                    c->stream->bytes_served += len;
2276

    
2277
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2278
                    /* RTP packets are sent inside the RTSP TCP connection */
2279
                    ByteIOContext pb1, *pb = &pb1;
2280
                    int interleaved_index, size;
2281
                    uint8_t header[4];
2282
                    HTTPContext *rtsp_c;
2283

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

    
2313
                    /* send everything we can NOW */
2314
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2315
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2316
                    if (len > 0) {
2317
                        rtsp_c->packet_buffer_ptr += len;
2318
                    }
2319
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2320
                        /* if we could not send all the data, we will
2321
                           send it later, so a new state is needed to
2322
                           "lock" the RTSP TCP connection */
2323
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2324
                        break;
2325
                    } else {
2326
                        /* all data has been sent */
2327
                        av_freep(&c->packet_buffer);
2328
                    }
2329
                } else {
2330
                    /* send RTP packet directly in UDP */
2331
                    c->buffer_ptr += 4;
2332
                    url_write(c->rtp_handles[c->packet_stream_index],
2333
                              c->buffer_ptr, len);
2334
                    c->buffer_ptr += len;
2335
                    /* here we continue as we can send several packets per 10 ms slot */
2336
                }
2337
            } else {
2338
                /* TCP data output */
2339
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2340
                if (len < 0) {
2341
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2342
                        ff_neterrno() != FF_NETERROR(EINTR)) {
2343
                        /* error : close connection */
2344
                        return -1;
2345
                    } else {
2346
                        return 0;
2347
                    }
2348
                } else {
2349
                    c->buffer_ptr += len;
2350
                }
2351
                c->data_count += len;
2352
                update_datarate(&c->datarate, c->data_count);
2353
                if (c->stream)
2354
                    c->stream->bytes_served += len;
2355
                break;
2356
            }
2357
        }
2358
    } /* for(;;) */
2359
    return 0;
2360
}
2361

    
2362
static int http_start_receive_data(HTTPContext *c)
2363
{
2364
    int fd;
2365

    
2366
    if (c->stream->feed_opened)
2367
        return -1;
2368

    
2369
    /* Don't permit writing to this one */
2370
    if (c->stream->readonly)
2371
        return -1;
2372

    
2373
    /* open feed */
2374
    fd = open(c->stream->feed_filename, O_RDWR);
2375
    if (fd < 0)
2376
        return -1;
2377
    c->feed_fd = fd;
2378

    
2379
    c->stream->feed_write_index = ffm_read_write_index(fd);
2380
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2381
    lseek(fd, 0, SEEK_SET);
2382

    
2383
    /* init buffer input */
2384
    c->buffer_ptr = c->buffer;
2385
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2386
    c->stream->feed_opened = 1;
2387
    return 0;
2388
}
2389

    
2390
static int http_receive_data(HTTPContext *c)
2391
{
2392
    HTTPContext *c1;
2393

    
2394
    if (c->buffer_end > c->buffer_ptr) {
2395
        int len;
2396

    
2397
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2398
        if (len < 0) {
2399
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2400
                ff_neterrno() != FF_NETERROR(EINTR)) {
2401
                /* error : close connection */
2402
                goto fail;
2403
            }
2404
        } else if (len == 0) {
2405
            /* end of connection : close it */
2406
            goto fail;
2407
        } else {
2408
            c->buffer_ptr += len;
2409
            c->data_count += len;
2410
            update_datarate(&c->datarate, c->data_count);
2411
        }
2412
    }
2413

    
2414
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2415
        if (c->buffer[0] != 'f' ||
2416
            c->buffer[1] != 'm') {
2417
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2418
            goto fail;
2419
        }
2420
    }
2421

    
2422
    if (c->buffer_ptr >= c->buffer_end) {
2423
        FFStream *feed = c->stream;
2424
        /* a packet has been received : write it in the store, except
2425
           if header */
2426
        if (c->data_count > FFM_PACKET_SIZE) {
2427

    
2428
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2429
            /* XXX: use llseek or url_seek */
2430
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2431
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2432

    
2433
            feed->feed_write_index += FFM_PACKET_SIZE;
2434
            /* update file size */
2435
            if (feed->feed_write_index > c->stream->feed_size)
2436
                feed->feed_size = feed->feed_write_index;
2437

    
2438
            /* handle wrap around if max file size reached */
2439
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2440
                feed->feed_write_index = FFM_PACKET_SIZE;
2441

    
2442
            /* write index */
2443
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2444

    
2445
            /* wake up any waiting connections */
2446
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2447
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2448
                    c1->stream->feed == c->stream->feed) {
2449
                    c1->state = HTTPSTATE_SEND_DATA;
2450
                }
2451
            }
2452
        } else {
2453
            /* We have a header in our hands that contains useful data */
2454
            AVFormatContext s;
2455
            AVInputFormat *fmt_in;
2456
            ByteIOContext *pb = &s.pb;
2457
            int i;
2458

    
2459
            memset(&s, 0, sizeof(s));
2460

    
2461
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2462
            pb->buf_end = c->buffer_end;        /* ?? */
2463
            pb->is_streamed = 1;
2464

    
2465
            /* use feed output format name to find corresponding input format */
2466
            fmt_in = av_find_input_format(feed->fmt->name);
2467
            if (!fmt_in)
2468
                goto fail;
2469

    
2470
            if (fmt_in->priv_data_size > 0) {
2471
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2472
                if (!s.priv_data)
2473
                    goto fail;
2474
            } else
2475
                s.priv_data = NULL;
2476

    
2477
            if (fmt_in->read_header(&s, 0) < 0) {
2478
                av_freep(&s.priv_data);
2479
                goto fail;
2480
            }
2481

    
2482
            /* Now we have the actual streams */
2483
            if (s.nb_streams != feed->nb_streams) {
2484
                av_freep(&s.priv_data);
2485
                goto fail;
2486
            }
2487
            for (i = 0; i < s.nb_streams; i++) {
2488
                memcpy(feed->streams[i]->codec,
2489
                       s.streams[i]->codec, sizeof(AVCodecContext));
2490
            }
2491
            av_freep(&s.priv_data);
2492
        }
2493
        c->buffer_ptr = c->buffer;
2494
    }
2495

    
2496
    return 0;
2497
 fail:
2498
    c->stream->feed_opened = 0;
2499
    close(c->feed_fd);
2500
    return -1;
2501
}
2502

    
2503
/********************************************************************/
2504
/* RTSP handling */
2505

    
2506
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2507
{
2508
    const char *str;
2509
    time_t ti;
2510
    char *p;
2511
    char buf2[32];
2512

    
2513
    switch(error_number) {
2514
    case RTSP_STATUS_OK:
2515
        str = "OK";
2516
        break;
2517
    case RTSP_STATUS_METHOD:
2518
        str = "Method Not Allowed";
2519
        break;
2520
    case RTSP_STATUS_BANDWIDTH:
2521
        str = "Not Enough Bandwidth";
2522
        break;
2523
    case RTSP_STATUS_SESSION:
2524
        str = "Session Not Found";
2525
        break;
2526
    case RTSP_STATUS_STATE:
2527
        str = "Method Not Valid in This State";
2528
        break;
2529
    case RTSP_STATUS_AGGREGATE:
2530
        str = "Aggregate operation not allowed";
2531
        break;
2532
    case RTSP_STATUS_ONLY_AGGREGATE:
2533
        str = "Only aggregate operation allowed";
2534
        break;
2535
    case RTSP_STATUS_TRANSPORT:
2536
        str = "Unsupported transport";
2537
        break;
2538
    case RTSP_STATUS_INTERNAL:
2539
        str = "Internal Server Error";
2540
        break;
2541
    case RTSP_STATUS_SERVICE:
2542
        str = "Service Unavailable";
2543
        break;
2544
    case RTSP_STATUS_VERSION:
2545
        str = "RTSP Version not supported";
2546
        break;
2547
    default:
2548
        str = "Unknown Error";
2549
        break;
2550
    }
2551

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

    
2555
    /* output GMT time */
2556
    ti = time(NULL);
2557
    p = ctime(&ti);
2558
    strcpy(buf2, p);
2559
    p = buf2 + strlen(p) - 1;
2560
    if (*p == '\n')
2561
        *p = '\0';
2562
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2563
}
2564

    
2565
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2566
{
2567
    rtsp_reply_header(c, error_number);
2568
    url_fprintf(c->pb, "\r\n");
2569
}
2570

    
2571
static int rtsp_parse_request(HTTPContext *c)
2572
{
2573
    const char *p, *p1, *p2;
2574
    char cmd[32];
2575
    char url[1024];
2576
    char protocol[32];
2577
    char line[1024];
2578
    ByteIOContext pb1;
2579
    int len;
2580
    RTSPHeader header1, *header = &header1;
2581

    
2582
    c->buffer_ptr[0] = '\0';
2583
    p = c->buffer;
2584

    
2585
    get_word(cmd, sizeof(cmd), &p);
2586
    get_word(url, sizeof(url), &p);
2587
    get_word(protocol, sizeof(protocol), &p);
2588

    
2589
    pstrcpy(c->method, sizeof(c->method), cmd);
2590
    pstrcpy(c->url, sizeof(c->url), url);
2591
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2592

    
2593
    c->pb = &pb1;
2594
    if (url_open_dyn_buf(c->pb) < 0) {
2595
        /* XXX: cannot do more */
2596
        c->pb = NULL; /* safety */
2597
        return -1;
2598
    }
2599

    
2600
    /* check version name */
2601
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2602
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2603
        goto the_end;
2604
    }
2605

    
2606
    /* parse each header line */
2607
    memset(header, 0, sizeof(RTSPHeader));
2608
    /* skip to next line */
2609
    while (*p != '\n' && *p != '\0')
2610
        p++;
2611
    if (*p == '\n')
2612
        p++;
2613
    while (*p != '\0') {
2614
        p1 = strchr(p, '\n');
2615
        if (!p1)
2616
            break;
2617
        p2 = p1;
2618
        if (p2 > p && p2[-1] == '\r')
2619
            p2--;
2620
        /* skip empty line */
2621
        if (p2 == p)
2622
            break;
2623
        len = p2 - p;
2624
        if (len > sizeof(line) - 1)
2625
            len = sizeof(line) - 1;
2626
        memcpy(line, p, len);
2627
        line[len] = '\0';
2628
        rtsp_parse_line(header, line);
2629
        p = p1 + 1;
2630
    }
2631

    
2632
    /* handle sequence number */
2633
    c->seq = header->seq;
2634

    
2635
    if (!strcmp(cmd, "DESCRIBE")) {
2636
        rtsp_cmd_describe(c, url);
2637
    } else if (!strcmp(cmd, "OPTIONS")) {
2638
        rtsp_cmd_options(c, url);
2639
    } else if (!strcmp(cmd, "SETUP")) {
2640
        rtsp_cmd_setup(c, url, header);
2641
    } else if (!strcmp(cmd, "PLAY")) {
2642
        rtsp_cmd_play(c, url, header);
2643
    } else if (!strcmp(cmd, "PAUSE")) {
2644
        rtsp_cmd_pause(c, url, header);
2645
    } else if (!strcmp(cmd, "TEARDOWN")) {
2646
        rtsp_cmd_teardown(c, url, header);
2647
    } else {
2648
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2649
    }
2650
 the_end:
2651
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2652
    c->pb = NULL; /* safety */
2653
    if (len < 0) {
2654
        /* XXX: cannot do more */
2655
        return -1;
2656
    }
2657
    c->buffer_ptr = c->pb_buffer;
2658
    c->buffer_end = c->pb_buffer + len;
2659
    c->state = RTSPSTATE_SEND_REPLY;
2660
    return 0;
2661
}
2662

    
2663
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2664
   AVFormatContext */
2665
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2666
                                   struct in_addr my_ip)
2667
{
2668
    ByteIOContext pb1, *pb = &pb1;
2669
    int i, payload_type, port, private_payload_type, j;
2670
    const char *ipstr, *title, *mediatype;
2671
    AVStream *st;
2672

    
2673
    if (url_open_dyn_buf(pb) < 0)
2674
        return -1;
2675

    
2676
    /* general media info */
2677

    
2678
    url_fprintf(pb, "v=0\n");
2679
    ipstr = inet_ntoa(my_ip);
2680
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2681
    title = stream->title;
2682
    if (title[0] == '\0')
2683
        title = "No Title";
2684
    url_fprintf(pb, "s=%s\n", title);
2685
    if (stream->comment[0] != '\0')
2686
        url_fprintf(pb, "i=%s\n", stream->comment);
2687
    if (stream->is_multicast) {
2688
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2689
    }
2690
    /* for each stream, we output the necessary info */
2691
    private_payload_type = RTP_PT_PRIVATE;
2692
    for(i = 0; i < stream->nb_streams; i++) {
2693
        st = stream->streams[i];
2694
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2695
            mediatype = "video";
2696
        } else {
2697
            switch(st->codec->codec_type) {
2698
            case CODEC_TYPE_AUDIO:
2699
                mediatype = "audio";
2700
                break;
2701
            case CODEC_TYPE_VIDEO:
2702
                mediatype = "video";
2703
                break;
2704
            default:
2705
                mediatype = "application";
2706
                break;
2707
            }
2708
        }
2709
        /* NOTE: the port indication is not correct in case of
2710
           unicast. It is not an issue because RTSP gives it */
2711
        payload_type = rtp_get_payload_type(st->codec);
2712
        if (payload_type < 0)
2713
            payload_type = private_payload_type++;
2714
        if (stream->is_multicast) {
2715
            port = stream->multicast_port + 2 * i;
2716
        } else {
2717
            port = 0;
2718
        }
2719
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2720
                    mediatype, port, payload_type);
2721
        if (payload_type >= RTP_PT_PRIVATE) {
2722
            /* for private payload type, we need to give more info */
2723
            switch(st->codec->codec_id) {
2724
            case CODEC_ID_MPEG4:
2725
                {
2726
                    uint8_t *data;
2727
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2728
                                payload_type, 90000);
2729
                    /* we must also add the mpeg4 header */
2730
                    data = st->codec->extradata;
2731
                    if (data) {
2732
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2733
                        for(j=0;j<st->codec->extradata_size;j++) {
2734
                            url_fprintf(pb, "%02x", data[j]);
2735
                        }
2736
                        url_fprintf(pb, "\n");
2737
                    }
2738
                }
2739
                break;
2740
            default:
2741
                /* XXX: add other codecs ? */
2742
                goto fail;
2743
            }
2744
        }
2745
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2746
    }
2747
    return url_close_dyn_buf(pb, pbuffer);
2748
 fail:
2749
    url_close_dyn_buf(pb, pbuffer);
2750
    av_free(*pbuffer);
2751
    return -1;
2752
}
2753

    
2754
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2755
{
2756
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2757
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2758
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2759
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2760
    url_fprintf(c->pb, "\r\n");
2761
}
2762

    
2763
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2764
{
2765
    FFStream *stream;
2766
    char path1[1024];
2767
    const char *path;
2768
    uint8_t *content;
2769
    int content_length, len;
2770
    struct sockaddr_in my_addr;
2771

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

    
2778
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2779
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2780
            !strcmp(path, stream->filename)) {
2781
            goto found;
2782
        }
2783
    }
2784
    /* no stream found */
2785
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2786
    return;
2787

    
2788
 found:
2789
    /* prepare the media description in sdp format */
2790

    
2791
    /* get the host IP */
2792
    len = sizeof(my_addr);
2793
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2794
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2795
    if (content_length < 0) {
2796
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2797
        return;
2798
    }
2799
    rtsp_reply_header(c, RTSP_STATUS_OK);
2800
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2801
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2802
    url_fprintf(c->pb, "\r\n");
2803
    put_buffer(c->pb, content, content_length);
2804
}
2805

    
2806
static HTTPContext *find_rtp_session(const char *session_id)
2807
{
2808
    HTTPContext *c;
2809

    
2810
    if (session_id[0] == '\0')
2811
        return NULL;
2812

    
2813
    for(c = first_http_ctx; c != NULL; c = c->next) {
2814
        if (!strcmp(c->session_id, session_id))
2815
            return c;
2816
    }
2817
    return NULL;
2818
}
2819

    
2820
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2821
{
2822
    RTSPTransportField *th;
2823
    int i;
2824

    
2825
    for(i=0;i<h->nb_transports;i++) {
2826
        th = &h->transports[i];
2827
        if (th->protocol == protocol)
2828
            return th;
2829
    }
2830
    return NULL;
2831
}
2832

    
2833
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2834
                           RTSPHeader *h)
2835
{
2836
    FFStream *stream;
2837
    int stream_index, port;
2838
    char buf[1024];
2839
    char path1[1024];
2840
    const char *path;
2841
    HTTPContext *rtp_c;
2842
    RTSPTransportField *th;
2843
    struct sockaddr_in dest_addr;
2844
    RTSPActionServerSetup setup;
2845

    
2846
    /* find which url is asked */
2847
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2848
    path = path1;
2849
    if (*path == '/')
2850
        path++;
2851

    
2852
    /* now check each stream */
2853
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2854
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2855
            /* accept aggregate filenames only if single stream */
2856
            if (!strcmp(path, stream->filename)) {
2857
                if (stream->nb_streams != 1) {
2858
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2859
                    return;
2860
                }
2861
                stream_index = 0;
2862
                goto found;
2863
            }
2864

    
2865
            for(stream_index = 0; stream_index < stream->nb_streams;
2866
                stream_index++) {
2867
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2868
                         stream->filename, stream_index);
2869
                if (!strcmp(path, buf))
2870
                    goto found;
2871
            }
2872
        }
2873
    }
2874
    /* no stream found */
2875
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2876
    return;
2877
 found:
2878

    
2879
    /* generate session id if needed */
2880
    if (h->session_id[0] == '\0') {
2881
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2882
                 av_random(&random_state), av_random(&random_state));
2883
    }
2884

    
2885
    /* find rtp session, and create it if none found */
2886
    rtp_c = find_rtp_session(h->session_id);
2887
    if (!rtp_c) {
2888
        /* always prefer UDP */
2889
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2890
        if (!th) {
2891
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2892
            if (!th) {
2893
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2894
                return;
2895
            }
2896
        }
2897

    
2898
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2899
                                   th->protocol);
2900
        if (!rtp_c) {
2901
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2902
            return;
2903
        }
2904

    
2905
        /* open input stream */
2906
        if (open_input_stream(rtp_c, "") < 0) {
2907
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2908
            return;
2909
        }
2910
    }
2911

    
2912
    /* test if stream is OK (test needed because several SETUP needs
2913
       to be done for a given file) */
2914
    if (rtp_c->stream != stream) {
2915
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2916
        return;
2917
    }
2918

    
2919
    /* test if stream is already set up */
2920
    if (rtp_c->rtp_ctx[stream_index]) {
2921
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2922
        return;
2923
    }
2924

    
2925
    /* check transport */
2926
    th = find_transport(h, rtp_c->rtp_protocol);
2927
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2928
                th->client_port_min <= 0)) {
2929
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2930
        return;
2931
    }
2932

    
2933
    /* setup default options */
2934
    setup.transport_option[0] = '\0';
2935
    dest_addr = rtp_c->from_addr;
2936
    dest_addr.sin_port = htons(th->client_port_min);
2937

    
2938
    /* setup stream */
2939
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2940
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2941
        return;
2942
    }
2943

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

    
2949
    switch(rtp_c->rtp_protocol) {
2950
    case RTSP_PROTOCOL_RTP_UDP:
2951
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2952
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2953
                    "client_port=%d-%d;server_port=%d-%d",
2954
                    th->client_port_min, th->client_port_min + 1,
2955
                    port, port + 1);
2956
        break;
2957
    case RTSP_PROTOCOL_RTP_TCP:
2958
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2959
                    stream_index * 2, stream_index * 2 + 1);
2960
        break;
2961
    default:
2962
        break;
2963
    }
2964
    if (setup.transport_option[0] != '\0') {
2965
        url_fprintf(c->pb, ";%s", setup.transport_option);
2966
    }
2967
    url_fprintf(c->pb, "\r\n");
2968

    
2969

    
2970
    url_fprintf(c->pb, "\r\n");
2971
}
2972

    
2973

    
2974
/* find an rtp connection by using the session ID. Check consistency
2975
   with filename */
2976
static HTTPContext *find_rtp_session_with_url(const char *url,
2977
                                              const char *session_id)
2978
{
2979
    HTTPContext *rtp_c;
2980
    char path1[1024];
2981
    const char *path;
2982
    char buf[1024];
2983
    int s;
2984

    
2985
    rtp_c = find_rtp_session(session_id);
2986
    if (!rtp_c)
2987
        return NULL;
2988

    
2989
    /* find which url is asked */
2990
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2991
    path = path1;
2992
    if (*path == '/')
2993
        path++;
2994
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2995
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2996
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2997
        rtp_c->stream->filename, s);
2998
      if(!strncmp(path, buf, sizeof(buf))) {
2999
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3000
        return rtp_c;
3001
      }
3002
    }
3003
    return NULL;
3004
}
3005

    
3006
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3007
{
3008
    HTTPContext *rtp_c;
3009

    
3010
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3011
    if (!rtp_c) {
3012
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3013
        return;
3014
    }
3015

    
3016
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3017
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3018
        rtp_c->state != HTTPSTATE_READY) {
3019
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3020
        return;
3021
    }
3022

    
3023
#if 0
3024
    /* XXX: seek in stream */
3025
    if (h->range_start != AV_NOPTS_VALUE) {
3026
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3027
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3028
    }
3029
#endif
3030

    
3031
    rtp_c->state = HTTPSTATE_SEND_DATA;
3032

    
3033
    /* now everything is OK, so we can send the connection parameters */
3034
    rtsp_reply_header(c, RTSP_STATUS_OK);
3035
    /* session ID */
3036
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3037
    url_fprintf(c->pb, "\r\n");
3038
}
3039

    
3040
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3041
{
3042
    HTTPContext *rtp_c;
3043

    
3044
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3045
    if (!rtp_c) {
3046
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3047
        return;
3048
    }
3049

    
3050
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3051
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3052
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3053
        return;
3054
    }
3055

    
3056
    rtp_c->state = HTTPSTATE_READY;
3057
    rtp_c->first_pts = AV_NOPTS_VALUE;
3058
    /* now everything is OK, so we can send the connection parameters */
3059
    rtsp_reply_header(c, RTSP_STATUS_OK);
3060
    /* session ID */
3061
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3062
    url_fprintf(c->pb, "\r\n");
3063
}
3064

    
3065
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3066
{
3067
    HTTPContext *rtp_c;
3068
    char session_id[32];
3069

    
3070
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3071
    if (!rtp_c) {
3072
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3073
        return;
3074
    }
3075

    
3076
    pstrcpy(session_id, sizeof(session_id), rtp_c->session_id);
3077

    
3078
    /* abort the session */
3079
    close_connection(rtp_c);
3080

    
3081
    /* now everything is OK, so we can send the connection parameters */
3082
    rtsp_reply_header(c, RTSP_STATUS_OK);
3083
    /* session ID */
3084
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3085
    url_fprintf(c->pb, "\r\n");
3086
}
3087

    
3088

    
3089
/********************************************************************/
3090
/* RTP handling */
3091

    
3092
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3093
                                       FFStream *stream, const char *session_id,
3094
                                       enum RTSPProtocol rtp_protocol)
3095
{
3096
    HTTPContext *c = NULL;
3097
    const char *proto_str;
3098

    
3099
    /* XXX: should output a warning page when coming
3100
       close to the connection limit */
3101
    if (nb_connections >= nb_max_connections)
3102
        goto fail;
3103

    
3104
    /* add a new connection */
3105
    c = av_mallocz(sizeof(HTTPContext));
3106
    if (!c)
3107
        goto fail;
3108

    
3109
    c->fd = -1;
3110
    c->poll_entry = NULL;
3111
    c->from_addr = *from_addr;
3112
    c->buffer_size = IOBUFFER_INIT_SIZE;
3113
    c->buffer = av_malloc(c->buffer_size);
3114
    if (!c->buffer)
3115
        goto fail;
3116
    nb_connections++;
3117
    c->stream = stream;
3118
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3119
    c->state = HTTPSTATE_READY;
3120
    c->is_packetized = 1;
3121
    c->rtp_protocol = rtp_protocol;
3122

    
3123
    /* protocol is shown in statistics */
3124
    switch(c->rtp_protocol) {
3125
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3126
        proto_str = "MCAST";
3127
        break;
3128
    case RTSP_PROTOCOL_RTP_UDP:
3129
        proto_str = "UDP";
3130
        break;
3131
    case RTSP_PROTOCOL_RTP_TCP:
3132
        proto_str = "TCP";
3133
        break;
3134
    default:
3135
        proto_str = "???";
3136
        break;
3137
    }
3138
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3139
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3140

    
3141
    current_bandwidth += stream->bandwidth;
3142

    
3143
    c->next = first_http_ctx;
3144
    first_http_ctx = c;
3145
    return c;
3146

    
3147
 fail:
3148
    if (c) {
3149
        av_free(c->buffer);
3150
        av_free(c);
3151
    }
3152
    return NULL;
3153
}
3154

    
3155
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3156
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3157
   used. */
3158
static int rtp_new_av_stream(HTTPContext *c,
3159
                             int stream_index, struct sockaddr_in *dest_addr,
3160
                             HTTPContext *rtsp_c)
3161
{
3162
    AVFormatContext *ctx;
3163
    AVStream *st;
3164
    char *ipaddr;
3165
    URLContext *h;
3166
    uint8_t *dummy_buf;
3167
    char buf2[32];
3168
    int max_packet_size;
3169

    
3170
    /* now we can open the relevant output stream */
3171
    ctx = av_alloc_format_context();
3172
    if (!ctx)
3173
        return -1;
3174
    ctx->oformat = &rtp_muxer;
3175

    
3176
    st = av_mallocz(sizeof(AVStream));
3177
    if (!st)
3178
        goto fail;
3179
    st->codec= avcodec_alloc_context();
3180
    ctx->nb_streams = 1;
3181
    ctx->streams[0] = st;
3182

    
3183
    if (!c->stream->feed ||
3184
        c->stream->feed == c->stream) {
3185
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3186
    } else {
3187
        memcpy(st,
3188
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3189
               sizeof(AVStream));
3190
    }
3191
    st->priv_data = NULL;
3192

    
3193
    /* build destination RTP address */
3194
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3195

    
3196
    switch(c->rtp_protocol) {
3197
    case RTSP_PROTOCOL_RTP_UDP:
3198
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3199
        /* RTP/UDP case */
3200

    
3201
        /* XXX: also pass as parameter to function ? */
3202
        if (c->stream->is_multicast) {
3203
            int ttl;
3204
            ttl = c->stream->multicast_ttl;
3205
            if (!ttl)
3206
                ttl = 16;
3207
            snprintf(ctx->filename, sizeof(ctx->filename),
3208
                     "rtp://%s:%d?multicast=1&ttl=%d",
3209
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3210
        } else {
3211
            snprintf(ctx->filename, sizeof(ctx->filename),
3212
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3213
        }
3214

    
3215
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3216
            goto fail;
3217
        c->rtp_handles[stream_index] = h;
3218
        max_packet_size = url_get_max_packet_size(h);
3219
        break;
3220
    case RTSP_PROTOCOL_RTP_TCP:
3221
        /* RTP/TCP case */
3222
        c->rtsp_c = rtsp_c;
3223
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3224
        break;
3225
    default:
3226
        goto fail;
3227
    }
3228

    
3229
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3230
             ipaddr, ntohs(dest_addr->sin_port),
3231
             ctime1(buf2),
3232
             c->stream->filename, stream_index, c->protocol);
3233

    
3234
    /* normally, no packets should be output here, but the packet size may be checked */
3235
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3236
        /* XXX: close stream */
3237
        goto fail;
3238
    }
3239
    av_set_parameters(ctx, NULL);
3240
    if (av_write_header(ctx) < 0) {
3241
    fail:
3242
        if (h)
3243
            url_close(h);
3244
        av_free(ctx);
3245
        return -1;
3246
    }
3247
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3248
    av_free(dummy_buf);
3249

    
3250
    c->rtp_ctx[stream_index] = ctx;
3251
    return 0;
3252
}
3253

    
3254
/********************************************************************/
3255
/* ffserver initialization */
3256

    
3257
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3258
{
3259
    AVStream *fst;
3260

    
3261
    fst = av_mallocz(sizeof(AVStream));
3262
    if (!fst)
3263
        return NULL;
3264
    fst->codec= avcodec_alloc_context();
3265
    fst->priv_data = av_mallocz(sizeof(FeedData));
3266
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3267
    fst->codec->coded_frame = &dummy_frame;
3268
    fst->index = stream->nb_streams;
3269
    av_set_pts_info(fst, 33, 1, 90000);
3270
    stream->streams[stream->nb_streams++] = fst;
3271
    return fst;
3272
}
3273

    
3274
/* return the stream number in the feed */
3275
static int add_av_stream(FFStream *feed, AVStream *st)
3276
{
3277
    AVStream *fst;
3278
    AVCodecContext *av, *av1;
3279
    int i;
3280

    
3281
    av = st->codec;
3282
    for(i=0;i<feed->nb_streams;i++) {
3283
        st = feed->streams[i];
3284
        av1 = st->codec;
3285
        if (av1->codec_id == av->codec_id &&
3286
            av1->codec_type == av->codec_type &&
3287
            av1->bit_rate == av->bit_rate) {
3288

    
3289
            switch(av->codec_type) {
3290
            case CODEC_TYPE_AUDIO:
3291
                if (av1->channels == av->channels &&
3292
                    av1->sample_rate == av->sample_rate)
3293
                    goto found;
3294
                break;
3295
            case CODEC_TYPE_VIDEO:
3296
                if (av1->width == av->width &&
3297
                    av1->height == av->height &&
3298
                    av1->time_base.den == av->time_base.den &&
3299
                    av1->time_base.num == av->time_base.num &&
3300
                    av1->gop_size == av->gop_size)
3301
                    goto found;
3302
                break;
3303
            default:
3304
                av_abort();
3305
            }
3306
        }
3307
    }
3308

    
3309
    fst = add_av_stream1(feed, av);
3310
    if (!fst)
3311
        return -1;
3312
    return feed->nb_streams - 1;
3313
 found:
3314
    return i;
3315
}
3316

    
3317
static void remove_stream(FFStream *stream)
3318
{
3319
    FFStream **ps;
3320
    ps = &first_stream;
3321
    while (*ps != NULL) {
3322
        if (*ps == stream) {
3323
            *ps = (*ps)->next;
3324
        } else {
3325
            ps = &(*ps)->next;
3326
        }
3327
    }
3328
}
3329

    
3330
/* specific mpeg4 handling : we extract the raw parameters */
3331
static void extract_mpeg4_header(AVFormatContext *infile)
3332
{
3333
    int mpeg4_count, i, size;
3334
    AVPacket pkt;
3335
    AVStream *st;
3336
    const uint8_t *p;
3337

    
3338
    mpeg4_count = 0;
3339
    for(i=0;i<infile->nb_streams;i++) {
3340
        st = infile->streams[i];
3341
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3342
            st->codec->extradata_size == 0) {
3343
            mpeg4_count++;
3344
        }
3345
    }
3346
    if (!mpeg4_count)
3347
        return;
3348

    
3349
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3350
    while (mpeg4_count > 0) {
3351
        if (av_read_packet(infile, &pkt) < 0)
3352
            break;
3353
        st = infile->streams[pkt.stream_index];
3354
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3355
            st->codec->extradata_size == 0) {
3356
            av_freep(&st->codec->extradata);
3357
            /* fill extradata with the header */
3358
            /* XXX: we make hard suppositions here ! */
3359
            p = pkt.data;
3360
            while (p < pkt.data + pkt.size - 4) {
3361
                /* stop when vop header is found */
3362
                if (p[0] == 0x00 && p[1] == 0x00 &&
3363
                    p[2] == 0x01 && p[3] == 0xb6) {
3364
                    size = p - pkt.data;
3365
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3366
                    st->codec->extradata = av_malloc(size);
3367
                    st->codec->extradata_size = size;
3368
                    memcpy(st->codec->extradata, pkt.data, size);
3369
                    break;
3370
                }
3371
                p++;
3372
            }
3373
            mpeg4_count--;
3374
        }
3375
        av_free_packet(&pkt);
3376
    }
3377
}
3378

    
3379
/* compute the needed AVStream for each file */
3380
static void build_file_streams(void)
3381
{
3382
    FFStream *stream, *stream_next;
3383
    AVFormatContext *infile;
3384
    int i;
3385

    
3386
    /* gather all streams */
3387
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3388
        stream_next = stream->next;
3389
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3390
            !stream->feed) {
3391
            /* the stream comes from a file */
3392
            /* try to open the file */
3393
            /* open stream */
3394
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3395
            if (stream->fmt == &rtp_muxer) {
3396
                /* specific case : if transport stream output to RTP,
3397
                   we use a raw transport stream reader */
3398
                stream->ap_in->mpeg2ts_raw = 1;
3399
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3400
            }
3401

    
3402
            if (av_open_input_file(&infile, stream->feed_filename,
3403
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3404
                http_log("%s not found", stream->feed_filename);
3405
                /* remove stream (no need to spend more time on it) */
3406
            fail:
3407
                remove_stream(stream);
3408
            } else {
3409
                /* find all the AVStreams inside and reference them in
3410
                   'stream' */
3411
                if (av_find_stream_info(infile) < 0) {
3412
                    http_log("Could not find codec parameters from '%s'",
3413
                             stream->feed_filename);
3414
                    av_close_input_file(infile);
3415
                    goto fail;
3416
                }
3417
                extract_mpeg4_header(infile);
3418

    
3419
                for(i=0;i<infile->nb_streams;i++) {
3420
                    add_av_stream1(stream, infile->streams[i]->codec);
3421
                }
3422
                av_close_input_file(infile);
3423
            }
3424
        }
3425
    }
3426
}
3427

    
3428
/* compute the needed AVStream for each feed */
3429
static void build_feed_streams(void)
3430
{
3431
    FFStream *stream, *feed;
3432
    int i;
3433

    
3434
    /* gather all streams */
3435
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3436
        feed = stream->feed;
3437
        if (feed) {
3438
            if (!stream->is_feed) {
3439
                /* we handle a stream coming from a feed */
3440
                for(i=0;i<stream->nb_streams;i++) {
3441
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3442
                }
3443
            }
3444
        }
3445
    }
3446

    
3447
    /* gather all streams */
3448
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3449
        feed = stream->feed;
3450
        if (feed) {
3451
            if (stream->is_feed) {
3452
                for(i=0;i<stream->nb_streams;i++) {
3453
                    stream->feed_streams[i] = i;
3454
                }
3455
            }
3456
        }
3457
    }
3458

    
3459
    /* create feed files if needed */
3460
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3461
        int fd;
3462

    
3463
        if (url_exist(feed->feed_filename)) {
3464
            /* See if it matches */
3465
            AVFormatContext *s;
3466
            int matches = 0;
3467

    
3468
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3469
                /* Now see if it matches */
3470
                if (s->nb_streams == feed->nb_streams) {
3471
                    matches = 1;
3472
                    for(i=0;i<s->nb_streams;i++) {
3473
                        AVStream *sf, *ss;
3474
                        sf = feed->streams[i];
3475
                        ss = s->streams[i];
3476

    
3477
                        if (sf->index != ss->index ||
3478
                            sf->id != ss->id) {
3479
                            printf("Index & Id do not match for stream %d (%s)\n",
3480
                                   i, feed->feed_filename);
3481
                            matches = 0;
3482
                        } else {
3483
                            AVCodecContext *ccf, *ccs;
3484

    
3485
                            ccf = sf->codec;
3486
                            ccs = ss->codec;
3487
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3488

    
3489
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3490
                                printf("Codecs do not match for stream %d\n", i);
3491
                                matches = 0;
3492
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3493
                                printf("Codec bitrates do not match for stream %d\n", i);
3494
                                matches = 0;
3495
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3496
                                if (CHECK_CODEC(time_base.den) ||
3497
                                    CHECK_CODEC(time_base.num) ||
3498
                                    CHECK_CODEC(width) ||
3499
                                    CHECK_CODEC(height)) {
3500
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3501
                                    matches = 0;
3502
                                }
3503
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3504
                                if (CHECK_CODEC(sample_rate) ||
3505
                                    CHECK_CODEC(channels) ||
3506
                                    CHECK_CODEC(frame_size)) {
3507
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3508
                                    matches = 0;
3509
                                }
3510
                            } else {
3511
                                printf("Unknown codec type\n");
3512
                                matches = 0;
3513
                            }
3514
                        }
3515
                        if (!matches) {
3516
                            break;
3517
                        }
3518
                    }
3519
                } else {
3520
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3521
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3522
                }
3523

    
3524
                av_close_input_file(s);
3525
            } else {
3526
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3527
                        feed->feed_filename);
3528
            }
3529
            if (!matches) {
3530
                if (feed->readonly) {
3531
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3532
                        feed->feed_filename);
3533
                    exit(1);
3534
                }
3535
                unlink(feed->feed_filename);
3536
            }
3537
        }
3538
        if (!url_exist(feed->feed_filename)) {
3539
            AVFormatContext s1, *s = &s1;
3540

    
3541
            if (feed->readonly) {
3542
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3543
                    feed->feed_filename);
3544
                exit(1);
3545
            }
3546

    
3547
            /* only write the header of the ffm file */
3548
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3549
                fprintf(stderr, "Could not open output feed file '%s'\n",
3550
                        feed->feed_filename);
3551
                exit(1);
3552
            }
3553
            s->oformat = feed->fmt;
3554
            s->nb_streams = feed->nb_streams;
3555
            for(i=0;i<s->nb_streams;i++) {
3556
                AVStream *st;
3557
                st = feed->streams[i];
3558
                s->streams[i] = st;
3559
            }
3560
            av_set_parameters(s, NULL);
3561
            if (av_write_header(s) < 0) {
3562
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3563
                exit(1);
3564
            }
3565
            /* XXX: need better api */
3566
            av_freep(&s->priv_data);
3567
            url_fclose(&s->pb);
3568
        }
3569
        /* get feed size and write index */
3570
        fd = open(feed->feed_filename, O_RDONLY);
3571
        if (fd < 0) {
3572
            fprintf(stderr, "Could not open output feed file '%s'\n",
3573
                    feed->feed_filename);
3574
            exit(1);
3575
        }
3576

    
3577
        feed->feed_write_index = ffm_read_write_index(fd);
3578
        feed->feed_size = lseek(fd, 0, SEEK_END);
3579
        /* ensure that we do not wrap before the end of file */
3580
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3581
            feed->feed_max_size = feed->feed_size;
3582

    
3583
        close(fd);
3584
    }
3585
}
3586

    
3587
/* compute the bandwidth used by each stream */
3588
static void compute_bandwidth(void)
3589
{
3590
    int bandwidth, i;
3591
    FFStream *stream;
3592

    
3593
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3594
        bandwidth = 0;
3595
        for(i=0;i<stream->nb_streams;i++) {
3596
            AVStream *st = stream->streams[i];
3597
            switch(st->codec->codec_type) {
3598
            case CODEC_TYPE_AUDIO:
3599
            case CODEC_TYPE_VIDEO:
3600
                bandwidth += st->codec->bit_rate;
3601
                break;
3602
            default:
3603
                break;
3604
            }
3605
        }
3606
        stream->bandwidth = (bandwidth + 999) / 1000;
3607
    }
3608
}
3609

    
3610
static void get_arg(char *buf, int buf_size, const char **pp)
3611
{
3612
    const char *p;
3613
    char *q;
3614
    int quote;
3615

    
3616
    p = *pp;
3617
    while (isspace(*p)) p++;
3618
    q = buf;
3619
    quote = 0;
3620
    if (*p == '\"' || *p == '\'')
3621
        quote = *p++;
3622
    for(;;) {
3623
        if (quote) {
3624
            if (*p == quote)
3625
                break;
3626
        } else {
3627
            if (isspace(*p))
3628
                break;
3629
        }
3630
        if (*p == '\0')
3631
            break;
3632
        if ((q - buf) < buf_size - 1)
3633
            *q++ = *p;
3634
        p++;
3635
    }
3636
    *q = '\0';
3637
    if (quote && *p == quote)
3638
        p++;
3639
    *pp = p;
3640
}
3641

    
3642
/* add a codec and set the default parameters */
3643
static void add_codec(FFStream *stream, AVCodecContext *av)
3644
{
3645
    AVStream *st;
3646

    
3647
    /* compute default parameters */
3648
    switch(av->codec_type) {
3649
    case CODEC_TYPE_AUDIO:
3650
        if (av->bit_rate == 0)
3651
            av->bit_rate = 64000;
3652
        if (av->sample_rate == 0)
3653
            av->sample_rate = 22050;
3654
        if (av->channels == 0)
3655
            av->channels = 1;
3656
        break;
3657
    case CODEC_TYPE_VIDEO:
3658
        if (av->bit_rate == 0)
3659
            av->bit_rate = 64000;
3660
        if (av->time_base.num == 0){
3661
            av->time_base.den = 5;
3662
            av->time_base.num = 1;
3663
        }
3664
        if (av->width == 0 || av->height == 0) {
3665
            av->width = 160;
3666
            av->height = 128;
3667
        }
3668
        /* Bitrate tolerance is less for streaming */
3669
        if (av->bit_rate_tolerance == 0)
3670
            av->bit_rate_tolerance = av->bit_rate / 4;
3671
        if (av->qmin == 0)
3672
            av->qmin = 3;
3673
        if (av->qmax == 0)
3674
            av->qmax = 31;
3675
        if (av->max_qdiff == 0)
3676
            av->max_qdiff = 3;
3677
        av->qcompress = 0.5;
3678
        av->qblur = 0.5;
3679

    
3680
        if (!av->nsse_weight)
3681
            av->nsse_weight = 8;
3682

    
3683
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3684
        av->me_method = ME_EPZS;
3685
        av->rc_buffer_aggressivity = 1.0;
3686

    
3687
        if (!av->rc_eq)
3688
            av->rc_eq = "tex^qComp";
3689
        if (!av->i_quant_factor)
3690
            av->i_quant_factor = -0.8;
3691
        if (!av->b_quant_factor)
3692
            av->b_quant_factor = 1.25;
3693
        if (!av->b_quant_offset)
3694
            av->b_quant_offset = 1.25;
3695
        if (!av->rc_max_rate)
3696
            av->rc_max_rate = av->bit_rate * 2;
3697

    
3698
        if (av->rc_max_rate && !av->rc_buffer_size) {
3699
            av->rc_buffer_size = av->rc_max_rate;
3700
        }
3701

    
3702

    
3703
        break;
3704
    default:
3705
        av_abort();
3706
    }
3707

    
3708
    st = av_mallocz(sizeof(AVStream));
3709
    if (!st)
3710
        return;
3711
    st->codec = avcodec_alloc_context();
3712
    stream->streams[stream->nb_streams++] = st;
3713
    memcpy(st->codec, av, sizeof(AVCodecContext));
3714
}
3715

    
3716
static int opt_audio_codec(const char *arg)
3717
{
3718
    AVCodec *p;
3719

    
3720
    p = first_avcodec;
3721
    while (p) {
3722
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3723
            break;
3724
        p = p->next;
3725
    }
3726
    if (p == NULL) {
3727
        return CODEC_ID_NONE;
3728
    }
3729

    
3730
    return p->id;
3731
}
3732

    
3733
static int opt_video_codec(const char *arg)
3734
{
3735
    AVCodec *p;
3736

    
3737
    p = first_avcodec;
3738
    while (p) {
3739
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3740
            break;
3741
        p = p->next;
3742
    }
3743
    if (p == NULL) {
3744
        return CODEC_ID_NONE;
3745
    }
3746

    
3747
    return p->id;
3748
}
3749

    
3750
/* simplistic plugin support */
3751

    
3752
#ifdef HAVE_DLOPEN
3753
static void load_module(const char *filename)
3754
{
3755
    void *dll;
3756
    void (*init_func)(void);
3757
    dll = dlopen(filename, RTLD_NOW);
3758
    if (!dll) {
3759
        fprintf(stderr, "Could not load module '%s' - %s\n",
3760
                filename, dlerror());
3761
        return;
3762
    }
3763

    
3764
    init_func = dlsym(dll, "ffserver_module_init");
3765
    if (!init_func) {
3766
        fprintf(stderr,
3767
                "%s: init function 'ffserver_module_init()' not found\n",
3768
                filename);
3769
        dlclose(dll);
3770
    }
3771

    
3772
    init_func();
3773
}
3774
#endif
3775

    
3776
static int parse_ffconfig(const char *filename)
3777
{
3778
    FILE *f;
3779
    char line[1024];
3780
    char cmd[64];
3781
    char arg[1024];
3782
    const char *p;
3783
    int val, errors, line_num;
3784
    FFStream **last_stream, *stream, *redirect;
3785
    FFStream **last_feed, *feed;
3786
    AVCodecContext audio_enc, video_enc;
3787
    int audio_id, video_id;
3788

    
3789
    f = fopen(filename, "r");
3790
    if (!f) {
3791
        perror(filename);
3792
        return -1;
3793
    }
3794

    
3795
    errors = 0;
3796
    line_num = 0;
3797
    first_stream = NULL;
3798
    last_stream = &first_stream;
3799
    first_feed = NULL;
3800
    last_feed = &first_feed;
3801
    stream = NULL;
3802
    feed = NULL;
3803
    redirect = NULL;
3804
    audio_id = CODEC_ID_NONE;
3805
    video_id = CODEC_ID_NONE;
3806
    for(;;) {
3807
        if (fgets(line, sizeof(line), f) == NULL)
3808
            break;
3809
        line_num++;
3810
        p = line;
3811
        while (isspace(*p))
3812
            p++;
3813
        if (*p == '\0' || *p == '#')
3814
            continue;
3815

    
3816
        get_arg(cmd, sizeof(cmd), &p);
3817

    
3818
        if (!strcasecmp(cmd, "Port")) {
3819
            get_arg(arg, sizeof(arg), &p);
3820
            val = atoi(arg);
3821
            if (val < 1 || val > 65536) {
3822
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3823
                        filename, line_num, arg);
3824
                errors++;
3825
            }
3826
            my_http_addr.sin_port = htons(val);
3827
        } else if (!strcasecmp(cmd, "BindAddress")) {
3828
            get_arg(arg, sizeof(arg), &p);
3829
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3830
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3831
                        filename, line_num, arg);
3832
                errors++;
3833
            }
3834
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3835
            ffserver_daemon = 0;
3836
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3837
            get_arg(arg, sizeof(arg), &p);
3838
            val = atoi(arg);
3839
            if (val < 1 || val > 65536) {
3840
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3841
                        filename, line_num, arg);
3842
                errors++;
3843
            }
3844
            my_rtsp_addr.sin_port = htons(atoi(arg));
3845
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3846
            get_arg(arg, sizeof(arg), &p);
3847
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3848
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3849
                        filename, line_num, arg);
3850
                errors++;
3851
            }
3852
        } else if (!strcasecmp(cmd, "MaxClients")) {
3853
            get_arg(arg, sizeof(arg), &p);
3854
            val = atoi(arg);
3855
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3856
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3857
                        filename, line_num, arg);
3858
                errors++;
3859
            } else {
3860
                nb_max_connections = val;
3861
            }
3862
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3863
            get_arg(arg, sizeof(arg), &p);
3864
            val = atoi(arg);
3865
            if (val < 10 || val > 100000) {
3866
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3867
                        filename, line_num, arg);
3868
                errors++;
3869
            } else {
3870
                max_bandwidth = val;
3871
            }
3872
        } else if (!strcasecmp(cmd, "CustomLog")) {
3873
            get_arg(logfilename, sizeof(logfilename), &p);
3874
        } else if (!strcasecmp(cmd, "<Feed")) {
3875
            /*********************************************/
3876
            /* Feed related options */
3877
            char *q;
3878
            if (stream || feed) {
3879
                fprintf(stderr, "%s:%d: Already in a tag\n",
3880
                        filename, line_num);
3881
            } else {
3882
                feed = av_mallocz(sizeof(FFStream));
3883
                /* add in stream list */
3884
                *last_stream = feed;
3885
                last_stream = &feed->next;
3886
                /* add in feed list */
3887
                *last_feed = feed;
3888
                last_feed = &feed->next_feed;
3889

    
3890
                get_arg(feed->filename, sizeof(feed->filename), &p);
3891
                q = strrchr(feed->filename, '>');
3892
                if (*q)
3893
                    *q = '\0';
3894
                feed->fmt = guess_format("ffm", NULL, NULL);
3895
                /* defaut feed file */
3896
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3897
                         "/tmp/%s.ffm", feed->filename);
3898
                feed->feed_max_size = 5 * 1024 * 1024;
3899
                feed->is_feed = 1;
3900
                feed->feed = feed; /* self feeding :-) */
3901
            }
3902
        } else if (!strcasecmp(cmd, "Launch")) {
3903
            if (feed) {
3904
                int i;
3905

    
3906
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3907

    
3908
                for (i = 0; i < 62; i++) {
3909
                    get_arg(arg, sizeof(arg), &p);
3910
                    if (!arg[0])
3911
                        break;
3912

    
3913
                    feed->child_argv[i] = av_strdup(arg);
3914
                }
3915

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

    
3918
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3919
                    "http://%s:%d/%s",
3920
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3921
                    inet_ntoa(my_http_addr.sin_addr),
3922
                    ntohs(my_http_addr.sin_port), feed->filename);
3923

    
3924
                if (ffserver_debug)
3925
                {
3926
                    int j;
3927
                    fprintf(stdout, "Launch commandline: ");
3928
                    for (j = 0; j <= i; j++)
3929
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3930
                    fprintf(stdout, "\n");
3931
                }
3932
            }
3933
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3934
            if (feed) {
3935
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3936
                feed->readonly = 1;
3937
            } else if (stream) {
3938
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3939
            }
3940
        } else if (!strcasecmp(cmd, "File")) {
3941
            if (feed) {
3942
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3943
            } else if (stream) {
3944
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3945
            }
3946
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3947
            if (feed) {
3948
                const char *p1;
3949
                double fsize;
3950

    
3951
                get_arg(arg, sizeof(arg), &p);
3952
                p1 = arg;
3953
                fsize = strtod(p1, (char **)&p1);
3954
                switch(toupper(*p1)) {
3955
                case 'K':
3956
                    fsize *= 1024;
3957
                    break;
3958
                case 'M':
3959
                    fsize *= 1024 * 1024;
3960
                    break;
3961
                case 'G':
3962
                    fsize *= 1024 * 1024 * 1024;
3963
                    break;
3964
                }
3965
                feed->feed_max_size = (int64_t)fsize;
3966
            }
3967
        } else if (!strcasecmp(cmd, "</Feed>")) {
3968
            if (!feed) {
3969
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3970
                        filename, line_num);
3971
                errors++;
3972
            }
3973
            feed = NULL;
3974
        } else if (!strcasecmp(cmd, "<Stream")) {
3975
            /*********************************************/
3976
            /* Stream related options */
3977
            char *q;
3978
            if (stream || feed) {
3979
                fprintf(stderr, "%s:%d: Already in a tag\n",
3980
                        filename, line_num);
3981
            } else {
3982
                stream = av_mallocz(sizeof(FFStream));
3983
                *last_stream = stream;
3984
                last_stream = &stream->next;
3985

    
3986
                get_arg(stream->filename, sizeof(stream->filename), &p);
3987
                q = strrchr(stream->filename, '>');
3988
                if (*q)
3989
                    *q = '\0';
3990
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3991
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3992
                memset(&video_enc, 0, sizeof(AVCodecContext));
3993
                audio_id = CODEC_ID_NONE;
3994
                video_id = CODEC_ID_NONE;
3995
                if (stream->fmt) {
3996
                    audio_id = stream->fmt->audio_codec;
3997
                    video_id = stream->fmt->video_codec;
3998
                }
3999
            }
4000
        } else if (!strcasecmp(cmd, "Feed")) {
4001
            get_arg(arg, sizeof(arg), &p);
4002
            if (stream) {
4003
                FFStream *sfeed;
4004

    
4005
                sfeed = first_feed;
4006
                while (sfeed != NULL) {
4007
                    if (!strcmp(sfeed->filename, arg))
4008
                        break;
4009
                    sfeed = sfeed->next_feed;
4010
                }
4011
                if (!sfeed) {
4012
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4013
                            filename, line_num, arg);
4014
                } else {
4015
                    stream->feed = sfeed;
4016
                }
4017
            }
4018
        } else if (!strcasecmp(cmd, "Format")) {
4019
            get_arg(arg, sizeof(arg), &p);
4020
            if (!strcmp(arg, "status")) {
4021
                stream->stream_type = STREAM_TYPE_STATUS;
4022
                stream->fmt = NULL;
4023
            } else {
4024
                stream->stream_type = STREAM_TYPE_LIVE;
4025
                /* jpeg cannot be used here, so use single frame jpeg */
4026
                if (!strcmp(arg, "jpeg"))
4027
                    strcpy(arg, "mjpeg");
4028
                stream->fmt = guess_stream_format(arg, NULL, NULL);
4029
                if (!stream->fmt) {
4030
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4031
                            filename, line_num, arg);
4032
                    errors++;
4033
                }
4034
            }
4035
            if (stream->fmt) {
4036
                audio_id = stream->fmt->audio_codec;
4037
                video_id = stream->fmt->video_codec;
4038
            }
4039
        } else if (!strcasecmp(cmd, "InputFormat")) {
4040
            get_arg(arg, sizeof(arg), &p);
4041
            stream->ifmt = av_find_input_format(arg);
4042
            if (!stream->ifmt) {
4043
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4044
                        filename, line_num, arg);
4045
            }
4046
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4047
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4048
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4049
            } else {
4050
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4051
                            filename, line_num);
4052
                errors++;
4053
            }
4054
        } else if (!strcasecmp(cmd, "Author")) {
4055
            if (stream) {
4056
                get_arg(stream->author, sizeof(stream->author), &p);
4057
            }
4058
        } else if (!strcasecmp(cmd, "Comment")) {
4059
            if (stream) {
4060
                get_arg(stream->comment, sizeof(stream->comment), &p);
4061
            }
4062
        } else if (!strcasecmp(cmd, "Copyright")) {
4063
            if (stream) {
4064
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4065
            }
4066
        } else if (!strcasecmp(cmd, "Title")) {
4067
            if (stream) {
4068
                get_arg(stream->title, sizeof(stream->title), &p);
4069
            }
4070
        } else if (!strcasecmp(cmd, "Preroll")) {
4071
            get_arg(arg, sizeof(arg), &p);
4072
            if (stream) {
4073
                stream->prebuffer = atof(arg) * 1000;
4074
            }
4075
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4076
            if (stream) {
4077
                stream->send_on_key = 1;
4078
            }
4079
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4080
            get_arg(arg, sizeof(arg), &p);
4081
            audio_id = opt_audio_codec(arg);
4082
            if (audio_id == CODEC_ID_NONE) {
4083
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4084
                        filename, line_num, arg);
4085
                errors++;
4086
            }
4087
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4088
            get_arg(arg, sizeof(arg), &p);
4089
            video_id = opt_video_codec(arg);
4090
            if (video_id == CODEC_ID_NONE) {
4091
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4092
                        filename, line_num, arg);
4093
                errors++;
4094
            }
4095
        } else if (!strcasecmp(cmd, "MaxTime")) {
4096
            get_arg(arg, sizeof(arg), &p);
4097
            if (stream) {
4098
                stream->max_time = atof(arg) * 1000;
4099
            }
4100
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4101
            get_arg(arg, sizeof(arg), &p);
4102
            if (stream) {
4103
                audio_enc.bit_rate = atoi(arg) * 1000;
4104
            }
4105
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4106
            get_arg(arg, sizeof(arg), &p);
4107
            if (stream) {
4108
                audio_enc.channels = atoi(arg);
4109
            }
4110
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4111
            get_arg(arg, sizeof(arg), &p);
4112
            if (stream) {
4113
                audio_enc.sample_rate = atoi(arg);
4114
            }
4115
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4116
            get_arg(arg, sizeof(arg), &p);
4117
            if (stream) {
4118
//                audio_enc.quality = atof(arg) * 1000;
4119
            }
4120
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4121
            if (stream) {
4122
                int minrate, maxrate;
4123

    
4124
                get_arg(arg, sizeof(arg), &p);
4125

    
4126
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4127
                    video_enc.rc_min_rate = minrate * 1000;
4128
                    video_enc.rc_max_rate = maxrate * 1000;
4129
                } else {
4130
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4131
                            filename, line_num, arg);
4132
                    errors++;
4133
                }
4134
            }
4135
        } else if (!strcasecmp(cmd, "Debug")) {
4136
            if (stream) {
4137
                get_arg(arg, sizeof(arg), &p);
4138
                video_enc.debug = strtol(arg,0,0);
4139
            }
4140
        } else if (!strcasecmp(cmd, "Strict")) {
4141
            if (stream) {
4142
                get_arg(arg, sizeof(arg), &p);
4143
                video_enc.strict_std_compliance = atoi(arg);
4144
            }
4145
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4146
            if (stream) {
4147
                get_arg(arg, sizeof(arg), &p);
4148
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4149
            }
4150
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4151
            if (stream) {
4152
                get_arg(arg, sizeof(arg), &p);
4153
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4154
            }
4155
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4156
            get_arg(arg, sizeof(arg), &p);
4157
            if (stream) {
4158
                video_enc.bit_rate = atoi(arg) * 1000;
4159
            }
4160
        } else if (!strcasecmp(cmd, "VideoSize")) {
4161
            get_arg(arg, sizeof(arg), &p);
4162
            if (stream) {
4163
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4164
                if ((video_enc.width % 16) != 0 ||
4165
                    (video_enc.height % 16) != 0) {
4166
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4167
                            filename, line_num);
4168
                    errors++;
4169
                }
4170
            }
4171
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4172
            get_arg(arg, sizeof(arg), &p);
4173
            if (stream) {
4174
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4175
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4176
            }
4177
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4178
            get_arg(arg, sizeof(arg), &p);
4179
            if (stream) {
4180
                video_enc.gop_size = atoi(arg);
4181
            }
4182
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4183
            if (stream) {
4184
                video_enc.gop_size = 1;
4185
            }
4186
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4187
            if (stream) {
4188
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4189
            }
4190
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4191
            if (stream) {
4192
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4193
                video_enc.flags |= CODEC_FLAG_4MV;
4194
            }
4195
        } else if (!strcasecmp(cmd, "VideoTag")) {
4196
            get_arg(arg, sizeof(arg), &p);
4197
            if ((strlen(arg) == 4) && stream) {
4198
                video_enc.codec_tag = ff_get_fourcc(arg);
4199
            }
4200
        } else if (!strcasecmp(cmd, "BitExact")) {
4201
            if (stream) {
4202
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4203
            }
4204
        } else if (!strcasecmp(cmd, "DctFastint")) {
4205
            if (stream) {
4206
                video_enc.dct_algo  = FF_DCT_FASTINT;
4207
            }
4208
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4209
            if (stream) {
4210
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4211
            }
4212
        } else if (!strcasecmp(cmd, "Qscale")) {
4213
            get_arg(arg, sizeof(arg), &p);
4214
            if (stream) {
4215
                video_enc.flags |= CODEC_FLAG_QSCALE;
4216
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4217
            }
4218
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4219
            get_arg(arg, sizeof(arg), &p);
4220
            if (stream) {
4221
                video_enc.max_qdiff = atoi(arg);
4222
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4223
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4224
                            filename, line_num);
4225
                    errors++;
4226
                }
4227
            }
4228
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4229
            get_arg(arg, sizeof(arg), &p);
4230
            if (stream) {
4231
                video_enc.qmax = atoi(arg);
4232
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4233
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4234
                            filename, line_num);
4235
                    errors++;
4236
                }
4237
            }
4238
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4239
            get_arg(arg, sizeof(arg), &p);
4240
            if (stream) {
4241
                video_enc.qmin = atoi(arg);
4242
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4243
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4244
                            filename, line_num);
4245
                    errors++;
4246
                }
4247
            }
4248
        } else if (!strcasecmp(cmd, "LumaElim")) {
4249
            get_arg(arg, sizeof(arg), &p);
4250
            if (stream) {
4251
                video_enc.luma_elim_threshold = atoi(arg);
4252
            }
4253
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4254
            get_arg(arg, sizeof(arg), &p);
4255
            if (stream) {
4256
                video_enc.chroma_elim_threshold = atoi(arg);
4257
            }
4258
        } else if (!strcasecmp(cmd, "LumiMask")) {
4259
            get_arg(arg, sizeof(arg), &p);
4260
            if (stream) {
4261
                video_enc.lumi_masking = atof(arg);
4262
            }
4263
        } else if (!strcasecmp(cmd, "DarkMask")) {
4264
            get_arg(arg, sizeof(arg), &p);
4265
            if (stream) {
4266
                video_enc.dark_masking = atof(arg);
4267
            }
4268
        } else if (!strcasecmp(cmd, "NoVideo")) {
4269
            video_id = CODEC_ID_NONE;
4270
        } else if (!strcasecmp(cmd, "NoAudio")) {
4271
            audio_id = CODEC_ID_NONE;
4272
        } else if (!strcasecmp(cmd, "ACL")) {
4273
            IPAddressACL acl;
4274

    
4275
            get_arg(arg, sizeof(arg), &p);
4276
            if (strcasecmp(arg, "allow") == 0) {
4277
                acl.action = IP_ALLOW;
4278
            } else if (strcasecmp(arg, "deny") == 0) {
4279
                acl.action = IP_DENY;
4280
            } else {
4281
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4282
                        filename, line_num, arg);
4283
                errors++;
4284
            }
4285

    
4286
            get_arg(arg, sizeof(arg), &p);
4287

    
4288
            if (resolve_host(&acl.first, arg) != 0) {
4289
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4290
                        filename, line_num, arg);
4291
                errors++;
4292
            } else {
4293
                acl.last = acl.first;
4294
            }
4295

    
4296
            get_arg(arg, sizeof(arg), &p);
4297

    
4298
            if (arg[0]) {
4299
                if (resolve_host(&acl.last, arg) != 0) {
4300
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4301
                            filename, line_num, arg);
4302
                    errors++;
4303
                }
4304
            }
4305

    
4306
            if (!errors) {
4307
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4308
                IPAddressACL **naclp = 0;
4309

    
4310
                acl.next = 0;
4311
                *nacl = acl;
4312

    
4313
                if (stream) {
4314
                    naclp = &stream->acl;
4315
                } else if (feed) {
4316
                    naclp = &feed->acl;
4317
                } else {
4318
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4319
                            filename, line_num);
4320
                    errors++;
4321
                }
4322

    
4323
                if (naclp) {
4324
                    while (*naclp)
4325
                        naclp = &(*naclp)->next;
4326

    
4327
                    *naclp = nacl;
4328
                }
4329
            }
4330
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4331
            get_arg(arg, sizeof(arg), &p);
4332
            if (stream) {
4333
                av_freep(&stream->rtsp_option);
4334
                stream->rtsp_option = av_strdup(arg);
4335
            }
4336
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4337
            get_arg(arg, sizeof(arg), &p);
4338
            if (stream) {
4339
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4340
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4341
                            filename, line_num, arg);
4342
                    errors++;
4343
                }
4344
                stream->is_multicast = 1;
4345
                stream->loop = 1; /* default is looping */
4346
            }
4347
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4348
            get_arg(arg, sizeof(arg), &p);
4349
            if (stream) {
4350
                stream->multicast_port = atoi(arg);
4351
            }
4352
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4353
            get_arg(arg, sizeof(arg), &p);
4354
            if (stream) {
4355
                stream->multicast_ttl = atoi(arg);
4356
            }
4357
        } else if (!strcasecmp(cmd, "NoLoop")) {
4358
            if (stream) {
4359
                stream->loop = 0;
4360
            }
4361
        } else if (!strcasecmp(cmd, "</Stream>")) {
4362
            if (!stream) {
4363
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4364
                        filename, line_num);
4365
                errors++;
4366
            }
4367
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4368
                if (audio_id != CODEC_ID_NONE) {
4369
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4370
                    audio_enc.codec_id = audio_id;
4371
                    add_codec(stream, &audio_enc);
4372
                }
4373
                if (video_id != CODEC_ID_NONE) {
4374
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4375
                    video_enc.codec_id = video_id;
4376
                    add_codec(stream, &video_enc);
4377
                }
4378
            }
4379
            stream = NULL;
4380
        } else if (!strcasecmp(cmd, "<Redirect")) {
4381
            /*********************************************/
4382
            char *q;
4383
            if (stream || feed || redirect) {
4384
                fprintf(stderr, "%s:%d: Already in a tag\n",
4385
                        filename, line_num);
4386
                errors++;
4387
            } else {
4388
                redirect = av_mallocz(sizeof(FFStream));
4389
                *last_stream = redirect;
4390
                last_stream = &redirect->next;
4391

    
4392
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4393
                q = strrchr(redirect->filename, '>');
4394
                if (*q)
4395
                    *q = '\0';
4396
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4397
            }
4398
        } else if (!strcasecmp(cmd, "URL")) {
4399
            if (redirect) {
4400
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4401
            }
4402
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4403
            if (!redirect) {
4404
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4405
                        filename, line_num);
4406
                errors++;
4407
            }
4408
            if (!redirect->feed_filename[0]) {
4409
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4410
                        filename, line_num);
4411
                errors++;
4412
            }
4413
            redirect = NULL;
4414
        } else if (!strcasecmp(cmd, "LoadModule")) {
4415
            get_arg(arg, sizeof(arg), &p);
4416
#ifdef HAVE_DLOPEN
4417
            load_module(arg);
4418
#else
4419
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4420
                    filename, line_num, arg);
4421
            errors++;
4422
#endif
4423
        } else {
4424
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4425
                    filename, line_num, cmd);
4426
            errors++;
4427
        }
4428
    }
4429

    
4430
    fclose(f);
4431
    if (errors)
4432
        return -1;
4433
    else
4434
        return 0;
4435
}
4436

    
4437
static void show_banner(void)
4438
{
4439
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4440
}
4441

    
4442
static void show_help(void)
4443
{
4444
    show_banner();
4445
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4446
           "Hyper fast multi format Audio/Video streaming server\n"
4447
           "\n"
4448
           "-L            : print the LICENSE\n"
4449
           "-h            : this help\n"
4450
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4451
           );
4452
}
4453

    
4454
static void show_license(void)
4455
{
4456
    show_banner();
4457
    printf(
4458
    "FFmpeg is free software; you can redistribute it and/or\n"
4459
    "modify it under the terms of the GNU Lesser General Public\n"
4460
    "License as published by the Free Software Foundation; either\n"
4461
    "version 2.1 of the License, or (at your option) any later version.\n"
4462
    "\n"
4463
    "FFmpeg is distributed in the hope that it will be useful,\n"
4464
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4465
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4466
    "Lesser General Public License for more details.\n"
4467
    "\n"
4468
    "You should have received a copy of the GNU Lesser General Public\n"
4469
    "License along with FFmpeg; if not, write to the Free Software\n"
4470
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4471
    );
4472
}
4473

    
4474
static void handle_child_exit(int sig)
4475
{
4476
    pid_t pid;
4477
    int status;
4478

    
4479
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4480
        FFStream *feed;
4481

    
4482
        for (feed = first_feed; feed; feed = feed->next) {
4483
            if (feed->pid == pid) {
4484
                int uptime = time(0) - feed->pid_start;
4485

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

    
4489
                if (uptime < 30) {
4490
                    /* Turn off any more restarts */
4491
                    feed->child_argv = 0;
4492
                }
4493
            }
4494
        }
4495
    }
4496

    
4497
    need_to_start_children = 1;
4498
}
4499

    
4500
int main(int argc, char **argv)
4501
{
4502
    const char *config_filename;
4503
    int c;
4504
    struct sigaction sigact;
4505

    
4506
    av_register_all();
4507

    
4508
    config_filename = "/etc/ffserver.conf";
4509

    
4510
    my_program_name = argv[0];
4511
    my_program_dir = getcwd(0, 0);
4512
    ffserver_daemon = 1;
4513

    
4514
    for(;;) {
4515
        c = getopt(argc, argv, "ndLh?f:");
4516
        if (c == -1)
4517
            break;
4518
        switch(c) {
4519
        case 'L':
4520
            show_license();
4521
            exit(1);
4522
        case '?':
4523
        case 'h':
4524
            show_help();
4525
            exit(1);
4526
        case 'n':
4527
            no_launch = 1;
4528
            break;
4529
        case 'd':
4530
            ffserver_debug = 1;
4531
            ffserver_daemon = 0;
4532
            break;
4533
        case 'f':
4534
            config_filename = optarg;
4535
            break;
4536
        default:
4537
            exit(2);
4538
        }
4539
    }
4540

    
4541
    putenv("http_proxy");               /* Kill the http_proxy */
4542

    
4543
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4544

    
4545
    /* address on which the server will handle HTTP connections */
4546
    my_http_addr.sin_family = AF_INET;
4547
    my_http_addr.sin_port = htons (8080);
4548
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4549

    
4550
    /* address on which the server will handle RTSP connections */
4551
    my_rtsp_addr.sin_family = AF_INET;
4552
    my_rtsp_addr.sin_port = htons (5454);
4553
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4554

    
4555
    nb_max_connections = 5;
4556
    max_bandwidth = 1000;
4557
    first_stream = NULL;
4558
    logfilename[0] = '\0';
4559

    
4560
    memset(&sigact, 0, sizeof(sigact));
4561
    sigact.sa_handler = handle_child_exit;
4562
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4563
    sigaction(SIGCHLD, &sigact, 0);
4564

    
4565
    if (parse_ffconfig(config_filename) < 0) {
4566
        fprintf(stderr, "Incorrect config file - exiting.\n");
4567
        exit(1);
4568
    }
4569

    
4570
    build_file_streams();
4571

    
4572
    build_feed_streams();
4573

    
4574
    compute_bandwidth();
4575

    
4576
    /* put the process in background and detach it from its TTY */
4577
    if (ffserver_daemon) {
4578
        int pid;
4579

    
4580
        pid = fork();
4581
        if (pid < 0) {
4582
            perror("fork");
4583
            exit(1);
4584
        } else if (pid > 0) {
4585
            /* parent : exit */
4586
            exit(0);
4587
        } else {
4588
            /* child */
4589
            setsid();
4590
            chdir("/");
4591
            close(0);
4592
            open("/dev/null", O_RDWR);
4593
            if (strcmp(logfilename, "-") != 0) {
4594
                close(1);
4595
                dup(0);
4596
            }
4597
            close(2);
4598
            dup(0);
4599
        }
4600
    }
4601

    
4602
    /* signal init */
4603
    signal(SIGPIPE, SIG_IGN);
4604

    
4605
    /* open log file if needed */
4606
    if (logfilename[0] != '\0') {
4607
        if (!strcmp(logfilename, "-"))
4608
            logfile = stdout;
4609
        else
4610
            logfile = fopen(logfilename, "w");
4611
    }
4612

    
4613
    if (http_server() < 0) {
4614
        fprintf(stderr, "Could not start server\n");
4615
        exit(1);
4616
    }
4617

    
4618
    return 0;
4619
}