Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 2d563d2f

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 "config.h"
23
#if HAVE_CLOSESOCKET != 1
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "avformat.h"
29

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

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

    
53
#undef exit
54

    
55
/* maximum number of simultaneous HTTP connections */
56
#define HTTP_MAX_CONNECTIONS 2000
57

    
58
enum HTTPState {
59
    HTTPSTATE_WAIT_REQUEST,
60
    HTTPSTATE_SEND_HEADER,
61
    HTTPSTATE_SEND_DATA_HEADER,
62
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
63
    HTTPSTATE_SEND_DATA_TRAILER,
64
    HTTPSTATE_RECEIVE_DATA,
65
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
66
    HTTPSTATE_READY,
67

    
68
    RTSPSTATE_WAIT_REQUEST,
69
    RTSPSTATE_SEND_REPLY,
70
    RTSPSTATE_SEND_PACKET,
71
};
72

    
73
const char *http_state[] = {
74
    "HTTP_WAIT_REQUEST",
75
    "HTTP_SEND_HEADER",
76

    
77
    "SEND_DATA_HEADER",
78
    "SEND_DATA",
79
    "SEND_DATA_TRAILER",
80
    "RECEIVE_DATA",
81
    "WAIT_FEED",
82
    "READY",
83

    
84
    "RTSP_WAIT_REQUEST",
85
    "RTSP_SEND_REPLY",
86
    "RTSP_SEND_PACKET",
87
};
88

    
89
#define IOBUFFER_INIT_SIZE 8192
90

    
91
/* timeouts are in ms */
92
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
93
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
94

    
95
#define SYNC_TIMEOUT (10 * 1000)
96

    
97
typedef struct {
98
    int64_t count1, count2;
99
    int64_t time1, time2;
100
} DataRateData;
101

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

    
147
    /* RTSP state specific */
148
    uint8_t *pb_buffer; /* XXX: use that in all the code */
149
    ByteIOContext *pb;
150
    int seq; /* RTSP sequence number */
151

    
152
    /* RTP state specific */
153
    enum RTSPProtocol rtp_protocol;
154
    char session_id[32]; /* session id */
155
    AVFormatContext *rtp_ctx[MAX_STREAMS];
156

    
157
    /* RTP/UDP specific */
158
    URLContext *rtp_handles[MAX_STREAMS];
159

    
160
    /* RTP/TCP specific */
161
    struct HTTPContext *rtsp_c;
162
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
163
} HTTPContext;
164

    
165
static AVFrame dummy_frame;
166

    
167
/* each generated stream is described here */
168
enum StreamType {
169
    STREAM_TYPE_LIVE,
170
    STREAM_TYPE_STATUS,
171
    STREAM_TYPE_REDIRECT,
172
};
173

    
174
enum IPAddressAction {
175
    IP_ALLOW = 1,
176
    IP_DENY,
177
};
178

    
179
typedef struct IPAddressACL {
180
    struct IPAddressACL *next;
181
    enum IPAddressAction action;
182
    /* These are in host order */
183
    struct in_addr first;
184
    struct in_addr last;
185
} IPAddressACL;
186

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

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

    
235
typedef struct FeedData {
236
    long long data_count;
237
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
238
} FeedData;
239

    
240
static struct sockaddr_in my_http_addr;
241
static struct sockaddr_in my_rtsp_addr;
242

    
243
static char logfilename[1024];
244
static HTTPContext *first_http_ctx;
245
static FFStream *first_feed;   /* contains only feeds */
246
static FFStream *first_stream; /* contains all streams, including feeds */
247

    
248
static void new_connection(int server_fd, int is_rtsp);
249
static void close_connection(HTTPContext *c);
250

    
251
/* HTTP handling */
252
static int handle_connection(HTTPContext *c);
253
static int http_parse_request(HTTPContext *c);
254
static int http_send_data(HTTPContext *c);
255
static void compute_stats(HTTPContext *c);
256
static int open_input_stream(HTTPContext *c, const char *info);
257
static int http_start_receive_data(HTTPContext *c);
258
static int http_receive_data(HTTPContext *c);
259

    
260
/* RTSP handling */
261
static int rtsp_parse_request(HTTPContext *c);
262
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
263
static void rtsp_cmd_options(HTTPContext *c, const char *url);
264
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
265
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
266
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
267
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
268

    
269
/* SDP handling */
270
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
271
                                   struct in_addr my_ip);
272

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

    
281
static const char *my_program_name;
282
static const char *my_program_dir;
283

    
284
static int ffserver_debug;
285
static int ffserver_daemon;
286
static int no_launch;
287
static int need_to_start_children;
288

    
289
static int nb_max_connections;
290
static int nb_connections;
291

    
292
static int max_bandwidth;
293
static int current_bandwidth;
294

    
295
static int64_t cur_time;           // Making this global saves on passing it around everywhere
296

    
297
static AVRandomState random_state;
298

    
299
static FILE *logfile = NULL;
300

    
301
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
302
{
303
    va_list ap;
304
    va_start(ap, fmt);
305

    
306
    if (logfile) {
307
        vfprintf(logfile, fmt, ap);
308
        fflush(logfile);
309
    }
310
    va_end(ap);
311
}
312

    
313
static char *ctime1(char *buf2)
314
{
315
    time_t ti;
316
    char *p;
317

    
318
    ti = time(NULL);
319
    p = ctime(&ti);
320
    strcpy(buf2, p);
321
    p = buf2 + strlen(p) - 1;
322
    if (*p == '\n')
323
        *p = '\0';
324
    return buf2;
325
}
326

    
327
static void log_connection(HTTPContext *c)
328
{
329
    char buf2[32];
330

    
331
    if (c->suppress_log)
332
        return;
333

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

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

    
353
/* In bytes per second */
354
static int compute_datarate(DataRateData *drd, int64_t count)
355
{
356
    if (cur_time == drd->time1)
357
        return 0;
358

    
359
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
360
}
361

    
362

    
363
static void start_children(FFStream *feed)
364
{
365
    if (no_launch)
366
        return;
367

    
368
    for (; feed; feed = feed->next) {
369
        if (feed->child_argv && !feed->pid) {
370
            feed->pid_start = time(0);
371

    
372
            feed->pid = fork();
373

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

    
384
                for (i = 3; i < 256; i++) {
385
                    close(i);
386
                }
387

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

    
398
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
399

    
400
                slash = strrchr(pathname, '/');
401
                if (!slash) {
402
                    slash = pathname;
403
                } else {
404
                    slash++;
405
                }
406
                strcpy(slash, "ffmpeg");
407

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

    
411
                signal(SIGPIPE, SIG_DFL);
412

    
413
                execvp(pathname, feed->child_argv);
414

    
415
                _exit(1);
416
            }
417
        }
418
    }
419
}
420

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

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

    
432
    tmp = 1;
433
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
434

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

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

    
450
    return server_fd;
451
}
452

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

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

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

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

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

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

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

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

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

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

    
523
    http_log("ffserver started.\n");
524

    
525
    start_children(first_feed);
526

    
527
    first_http_ctx = NULL;
528
    nb_connections = 0;
529

    
530
    start_multicast();
531

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

    
538
        poll_entry->fd = rtsp_server_fd;
539
        poll_entry->events = POLLIN;
540
        poll_entry++;
541

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

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

    
601
        cur_time = av_gettime() / 1000;
602

    
603
        if (need_to_start_children) {
604
            need_to_start_children = 0;
605
            start_children(first_feed);
606
        }
607

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

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

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

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

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

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

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

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

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

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

    
681
    start_wait_request(c, is_rtsp);
682

    
683
    return;
684

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

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

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

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

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

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

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

    
749
    ctx = &c->fmt_ctx;
750

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
966
            while (*q && *q != '\n' && isspace(*q))
967
                q++;
968

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

    
973
                q += 20;
974

    
975
                memset(rates, 0xff, ratelen);
976

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

    
981
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
982
                        break;
983
                    }
984
                    stream_no--;
985
                    if (stream_no < ratelen && stream_no >= 0) {
986
                        rates[stream_no] = rate_no;
987
                    }
988

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

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

    
1000
        p++;
1001
    }
1002

    
1003
    return 0;
1004
}
1005

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

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

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

    
1022
        /* Potential stream */
1023

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

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

    
1041
    return best;
1042
}
1043

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

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

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

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

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

    
1079
    return action_required;
1080
}
1081

    
1082

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1238
        p++;
1239
    }
1240

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

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

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

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

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

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

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

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

    
1313
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1314
        current_bandwidth += stream->bandwidth;
1315
    }
1316

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

    
1329
        /* prepare output buffer */
1330
        c->buffer_ptr = c->buffer;
1331
        c->buffer_end = q;
1332
        c->state = HTTPSTATE_SEND_HEADER;
1333
        return 0;
1334
    }
1335

    
1336
    if (redir_type != REDIR_NONE) {
1337
        char *hostinfo = 0;
1338

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

    
1348
            p++;
1349
        }
1350

    
1351
        if (hostinfo) {
1352
            char *eoh;
1353
            char hostbuf[260];
1354

    
1355
            while (isspace(*hostinfo))
1356
                hostinfo++;
1357

    
1358
            eoh = strchr(hostinfo, '\n');
1359
            if (eoh) {
1360
                if (eoh[-1] == '\r')
1361
                    eoh--;
1362

    
1363
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1364
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1365
                    hostbuf[eoh - hostinfo] = 0;
1366

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

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

    
1423
                            len = sizeof(my_addr);
1424
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1425

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

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

    
1452
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1453
        goto send_error;
1454
    }
1455

    
1456
    stream->conns_served++;
1457

    
1458
    /* XXX: add there authenticate and IP match */
1459

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

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

    
1481
                p++;
1482
            }
1483

    
1484
            if (logline) {
1485
                char *eol = strchr(logline, '\n');
1486

    
1487
                logline += 17;
1488

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

    
1497
#ifdef DEBUG_WMP
1498
            http_log("\nGot request:\n%s\n", c->buffer);
1499
#endif
1500

    
1501
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1502
                HTTPContext *wmpc;
1503

    
1504
                /* Now we have to find the client_id */
1505
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1506
                    if (wmpc->wmp_client_id == client_id)
1507
                        break;
1508
                }
1509

    
1510
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1511
                    wmpc->switch_pending = 1;
1512
            }
1513

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

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

    
1533
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1534
        goto send_stats;
1535

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

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

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

    
1554
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1555

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

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

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

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

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

    
1599
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1600
}
1601

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1766
                parameters[0] = 0;
1767

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

    
1786
        }
1787
        stream = stream->next;
1788
    }
1789

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1990

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2502
/********************************************************************/
2503
/* RTSP handling */
2504

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

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

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

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

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

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

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

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

    
2588
    av_strlcpy(c->method, cmd, sizeof(c->method));
2589
    av_strlcpy(c->url, url, sizeof(c->url));
2590
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2591

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

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

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

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

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

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

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

    
2675
    /* general media info */
2676

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2968

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

    
2972

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

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

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

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

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

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

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

    
3030
    rtp_c->state = HTTPSTATE_SEND_DATA;
3031

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

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

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

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

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

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

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

    
3075
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3076

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

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

    
3087

    
3088
/********************************************************************/
3089
/* RTP handling */
3090

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

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

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

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

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

    
3140
    current_bandwidth += stream->bandwidth;
3141

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3253
/********************************************************************/
3254
/* ffserver initialization */
3255

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3582
        close(fd);
3583
    }
3584
}
3585

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

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

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

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

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

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

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

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

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

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

    
3701

    
3702
        break;
3703
    default:
3704
        abort();
3705
    }
3706

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

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

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

    
3729
    return p->id;
3730
}
3731

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

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

    
3746
    return p->id;
3747
}
3748

    
3749
/* simplistic plugin support */
3750

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

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

    
3771
    init_func();
3772
}
3773
#endif
3774

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4496
    need_to_start_children = 1;
4497
}
4498

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

    
4505
    av_register_all();
4506

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

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

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

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

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

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

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

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

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

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

    
4569
    build_file_streams();
4570

    
4571
    build_feed_streams();
4572

    
4573
    compute_bandwidth();
4574

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

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

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

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

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

    
4617
    return 0;
4618
}