Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 88381412

History | View | Annotate | Download (150 KB)

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

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

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

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

    
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
                if (!ffserver_debug) {
388
                    i = open("/dev/null", O_RDWR);
389
                    if (i)
390
                        dup2(i, 0);
391
                    dup2(i, 1);
392
                    dup2(i, 2);
393
                    if (i)
394
                        close(i);
395
                }
396

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

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

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

    
409
                signal(SIGPIPE, SIG_DFL);
410

    
411
                execvp(pathname, feed->child_argv);
412

    
413
                _exit(1);
414
            }
415
        }
416
    }
417
}
418

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

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

    
430
    tmp = 1;
431
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
432

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

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

    
448
    return server_fd;
449
}
450

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

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

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

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

    
477
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
478
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
479
            if (!rtp_c)
480
                continue;
481

    
482
            if (open_input_stream(rtp_c, "") < 0) {
483
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
484
                        stream->filename);
485
                continue;
486
            }
487

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

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

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

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

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

    
521
    http_log("ffserver started.\n");
522

    
523
    start_children(first_feed);
524

    
525
    first_http_ctx = NULL;
526
    nb_connections = 0;
527

    
528
    start_multicast();
529

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

    
536
        poll_entry->fd = rtsp_server_fd;
537
        poll_entry->events = POLLIN;
538
        poll_entry++;
539

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

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

    
599
        cur_time = av_gettime() / 1000;
600

    
601
        if (need_to_start_children) {
602
            need_to_start_children = 0;
603
            start_children(first_feed);
604
        }
605

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

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

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

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

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

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

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

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

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

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

    
677
    start_wait_request(c, is_rtsp);
678

    
679
    return;
680

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

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

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

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

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

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

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

    
742
    ctx = &c->fmt_ctx;
743

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

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

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

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

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

    
773
static int handle_connection(HTTPContext *c)
774
{
775
    int len, ret;
776

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

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

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

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

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

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

    
886
        /* nothing to do, we'll be waken up by incoming feed packets */
887
        break;
888

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

    
950
static int extract_rates(char *rates, int ratelen, const char *request)
951
{
952
    const char *p;
953

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

    
958
            while (*q && *q != '\n' && isspace(*q))
959
                q++;
960

    
961
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
962
                int stream_no;
963
                int rate_no;
964

    
965
                q += 20;
966

    
967
                memset(rates, 0xff, ratelen);
968

    
969
                while (1) {
970
                    while (*q && *q != '\n' && *q != ':')
971
                        q++;
972

    
973
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
974
                        break;
975

    
976
                    stream_no--;
977
                    if (stream_no < ratelen && stream_no >= 0)
978
                        rates[stream_no] = rate_no;
979

    
980
                    while (*q && *q != '\n' && !isspace(*q))
981
                        q++;
982
                }
983

    
984
                return 1;
985
            }
986
        }
987
        p = strchr(p, '\n');
988
        if (!p)
989
            break;
990

    
991
        p++;
992
    }
993

    
994
    return 0;
995
}
996

    
997
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
998
{
999
    int i;
1000
    int best_bitrate = 100000000;
1001
    int best = -1;
1002

    
1003
    for (i = 0; i < feed->nb_streams; i++) {
1004
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1005

    
1006
        if (feed_codec->codec_id != codec->codec_id ||
1007
            feed_codec->sample_rate != codec->sample_rate ||
1008
            feed_codec->width != codec->width ||
1009
            feed_codec->height != codec->height)
1010
            continue;
1011

    
1012
        /* Potential stream */
1013

    
1014
        /* We want the fastest stream less than bit_rate, or the slowest
1015
         * faster than bit_rate
1016
         */
1017

    
1018
        if (feed_codec->bit_rate <= bit_rate) {
1019
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1020
                best_bitrate = feed_codec->bit_rate;
1021
                best = i;
1022
            }
1023
        } else {
1024
            if (feed_codec->bit_rate < best_bitrate) {
1025
                best_bitrate = feed_codec->bit_rate;
1026
                best = i;
1027
            }
1028
        }
1029
    }
1030

    
1031
    return best;
1032
}
1033

    
1034
static int modify_current_stream(HTTPContext *c, char *rates)
1035
{
1036
    int i;
1037
    FFStream *req = c->stream;
1038
    int action_required = 0;
1039

    
1040
    /* Not much we can do for a feed */
1041
    if (!req->feed)
1042
        return 0;
1043

    
1044
    for (i = 0; i < req->nb_streams; i++) {
1045
        AVCodecContext *codec = req->streams[i]->codec;
1046

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

    
1065
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1066
            action_required = 1;
1067
    }
1068

    
1069
    return action_required;
1070
}
1071

    
1072

    
1073
static void do_switch_stream(HTTPContext *c, int i)
1074
{
1075
    if (c->switch_feed_streams[i] >= 0) {
1076
#ifdef PHILIP
1077
        c->feed_streams[i] = c->switch_feed_streams[i];
1078
#endif
1079

    
1080
        /* Now update the stream */
1081
    }
1082
    c->switch_feed_streams[i] = -1;
1083
}
1084

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

    
1096
static void get_word(char *buf, int buf_size, const char **pp)
1097
{
1098
    const char *p;
1099
    char *q;
1100

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

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

    
1121
    for (acl = stream->acl; acl; acl = acl->next) {
1122
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1123
            return (acl->action == IP_ALLOW) ? 1 : 0;
1124
        last_action = acl->action;
1125
    }
1126

    
1127
    /* Nothing matched, so return not the last action */
1128
    return (last_action == IP_DENY) ? 1 : 0;
1129
}
1130

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

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

    
1157
enum RedirType {
1158
    REDIR_NONE,
1159
    REDIR_ASX,
1160
    REDIR_RAM,
1161
    REDIR_ASF,
1162
    REDIR_RTSP,
1163
    REDIR_SDP,
1164
};
1165

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

    
1182
    p = c->buffer;
1183
    get_word(cmd, sizeof(cmd), (const char **)&p);
1184
    av_strlcpy(c->method, cmd, sizeof(c->method));
1185

    
1186
    if (!strcmp(cmd, "GET"))
1187
        c->post = 0;
1188
    else if (!strcmp(cmd, "POST"))
1189
        c->post = 1;
1190
    else
1191
        return -1;
1192

    
1193
    get_word(url, sizeof(url), (const char **)&p);
1194
    av_strlcpy(c->url, url, sizeof(c->url));
1195

    
1196
    get_word(protocol, sizeof(protocol), (const char **)&p);
1197
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1198
        return -1;
1199

    
1200
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1201

    
1202
    if (ffserver_debug)
1203
        http_log("New connection: %s %s\n", cmd, url);
1204

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

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

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

    
1226
        p++;
1227
    }
1228

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

    
1248
    // "redirect" / request to index.html
1249
    if (!strlen(filename))
1250
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1251

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

    
1263
    c->stream = stream;
1264
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1265
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1266

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

    
1278
        /* prepare output buffer */
1279
        c->buffer_ptr = c->buffer;
1280
        c->buffer_end = q;
1281
        c->state = HTTPSTATE_SEND_HEADER;
1282
        return 0;
1283
    }
1284

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

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

    
1301
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1302
        current_bandwidth += stream->bandwidth;
1303

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

    
1316
        /* prepare output buffer */
1317
        c->buffer_ptr = c->buffer;
1318
        c->buffer_end = q;
1319
        c->state = HTTPSTATE_SEND_HEADER;
1320
        return 0;
1321
    }
1322

    
1323
    if (redir_type != REDIR_NONE) {
1324
        char *hostinfo = 0;
1325

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

    
1335
            p++;
1336
        }
1337

    
1338
        if (hostinfo) {
1339
            char *eoh;
1340
            char hostbuf[260];
1341

    
1342
            while (isspace(*hostinfo))
1343
                hostinfo++;
1344

    
1345
            eoh = strchr(hostinfo, '\n');
1346
            if (eoh) {
1347
                if (eoh[-1] == '\r')
1348
                    eoh--;
1349

    
1350
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1351
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1352
                    hostbuf[eoh - hostinfo] = 0;
1353

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

    
1406
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1407
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1408
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1409

    
1410
                            len = sizeof(my_addr);
1411
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1412

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

    
1430
                    /* prepare output buffer */
1431
                    c->buffer_ptr = c->buffer;
1432
                    c->buffer_end = q;
1433
                    c->state = HTTPSTATE_SEND_HEADER;
1434
                    return 0;
1435
                }
1436
            }
1437
        }
1438

    
1439
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1440
        goto send_error;
1441
    }
1442

    
1443
    stream->conns_served++;
1444

    
1445
    /* XXX: add there authenticate and IP match */
1446

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

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

    
1467
                p++;
1468
            }
1469

    
1470
            if (logline) {
1471
                char *eol = strchr(logline, '\n');
1472

    
1473
                logline += 17;
1474

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

    
1483
#ifdef DEBUG_WMP
1484
            http_log("\nGot request:\n%s\n", c->buffer);
1485
#endif
1486

    
1487
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1488
                HTTPContext *wmpc;
1489

    
1490
                /* Now we have to find the client_id */
1491
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1492
                    if (wmpc->wmp_client_id == client_id)
1493
                        break;
1494
                }
1495

    
1496
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1497
                    wmpc->switch_pending = 1;
1498
            }
1499

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

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

    
1518
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1519
        goto send_stats;
1520

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

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

    
1535
    /* for asf, we need extra headers */
1536
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1537
        /* Need to allocate a client id */
1538

    
1539
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1540

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

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

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

    
1576
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1577
{
1578
    static const char *suffix = " kMGTP";
1579
    const char *s;
1580

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

    
1583
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1584
}
1585

    
1586
static void compute_stats(HTTPContext *c)
1587
{
1588
    HTTPContext *c1;
1589
    FFStream *stream;
1590
    char *p;
1591
    time_t ti;
1592
    int i, len;
1593
    ByteIOContext pb1, *pb = &pb1;
1594

    
1595
    if (url_open_dyn_buf(pb) < 0) {
1596
        /* XXX: return an error ? */
1597
        c->buffer_ptr = c->buffer;
1598
        c->buffer_end = c->buffer;
1599
        return;
1600
    }
1601

    
1602
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1603
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1604
    url_fprintf(pb, "Pragma: no-cache\r\n");
1605
    url_fprintf(pb, "\r\n");
1606

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

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

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

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

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

    
1713
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1714
                {
1715
                    FILE *pid_stat;
1716
                    char ps_cmd[64];
1717

    
1718
                    /* This is somewhat linux specific I guess */
1719
                    snprintf(ps_cmd, sizeof(ps_cmd),
1720
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1721
                             stream->pid);
1722

    
1723
                    pid_stat = popen(ps_cmd, "r");
1724
                    if (pid_stat) {
1725
                        char cpuperc[10];
1726
                        char cpuused[64];
1727

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

    
1738
                url_fprintf(pb, "<p>");
1739
            }
1740
            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");
1741

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

    
1748
                parameters[0] = 0;
1749

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

    
1768
        }
1769
        stream = stream->next;
1770
    }
1771

    
1772
#if 0
1773
    {
1774
        float avg;
1775
        AVCodecContext *enc;
1776
        char buf[1024];
1777

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

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

    
1802
    /* connection status */
1803
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1804

    
1805
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1806
                 nb_connections, nb_max_connections);
1807

    
1808
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1809
                 current_bandwidth, max_bandwidth);
1810

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

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

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

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

    
1854
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1855
    c->buffer_ptr = c->pb_buffer;
1856
    c->buffer_end = c->pb_buffer + len;
1857
}
1858

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

    
1865
    if (!st->codec->codec) {
1866
        codec = avcodec_find_decoder(st->codec->codec_id);
1867
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1868
            st->codec->parse_only = 1;
1869
            if (avcodec_open(st->codec, codec) < 0)
1870
                st->codec->parse_only = 0;
1871
        }
1872
    }
1873
}
1874

    
1875
static int open_input_stream(HTTPContext *c, const char *info)
1876
{
1877
    char buf[128];
1878
    char input_filename[1024];
1879
    AVFormatContext *s;
1880
    int buf_size, i;
1881
    int64_t stream_pos;
1882

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

    
1907
#if 0
1908
    { time_t when = stream_pos / 1000000;
1909
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1910
    }
1911
#endif
1912

    
1913
    /* open stream */
1914
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1915
                           buf_size, c->stream->ap_in) < 0) {
1916
        http_log("%s not found", input_filename);
1917
        return -1;
1918
    }
1919
    c->fmt_in = s;
1920

    
1921
    /* open each parser */
1922
    for(i=0;i<s->nb_streams;i++)
1923
        open_parser(s, i);
1924

    
1925
    /* choose stream as clock source (we favorize video stream if
1926
       present) for packet sending */
1927
    c->pts_stream_index = 0;
1928
    for(i=0;i<c->stream->nb_streams;i++) {
1929
        if (c->pts_stream_index == 0 &&
1930
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1931
            c->pts_stream_index = i;
1932
        }
1933
    }
1934

    
1935
#if 1
1936
    if (c->fmt_in->iformat->read_seek)
1937
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1938
#endif
1939
    /* set the start time (needed for maxtime and RTP packet timing) */
1940
    c->start_time = cur_time;
1941
    c->first_pts = AV_NOPTS_VALUE;
1942
    return 0;
1943
}
1944

    
1945
/* return the server clock (in us) */
1946
static int64_t get_server_clock(HTTPContext *c)
1947
{
1948
    /* compute current pts value from system time */
1949
    return (cur_time - c->start_time) * 1000;
1950
}
1951

    
1952
/* return the estimated time at which the current packet must be sent
1953
   (in us) */
1954
static int64_t get_packet_send_clock(HTTPContext *c)
1955
{
1956
    int bytes_left, bytes_sent, frame_bytes;
1957

    
1958
    frame_bytes = c->cur_frame_bytes;
1959
    if (frame_bytes <= 0)
1960
        return c->cur_pts;
1961
    else {
1962
        bytes_left = c->buffer_end - c->buffer_ptr;
1963
        bytes_sent = frame_bytes - bytes_left;
1964
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1965
    }
1966
}
1967

    
1968

    
1969
static int http_prepare_data(HTTPContext *c)
1970
{
1971
    int i, len, ret;
1972
    AVFormatContext *ctx;
1973

    
1974
    av_freep(&c->pb_buffer);
1975
    switch(c->state) {
1976
    case HTTPSTATE_SEND_DATA_HEADER:
1977
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1978
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
1979
                   sizeof(c->fmt_ctx.author));
1980
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
1981
                   sizeof(c->fmt_ctx.comment));
1982
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
1983
                   sizeof(c->fmt_ctx.copyright));
1984
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
1985
                   sizeof(c->fmt_ctx.title));
1986

    
1987
        /* open output stream by using specified codecs */
1988
        c->fmt_ctx.oformat = c->stream->fmt;
1989
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
1990
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1991
            AVStream *st;
1992
            AVStream *src;
1993
            st = av_mallocz(sizeof(AVStream));
1994
            st->codec= avcodec_alloc_context();
1995
            c->fmt_ctx.streams[i] = st;
1996
            /* if file or feed, then just take streams from FFStream struct */
1997
            if (!c->stream->feed ||
1998
                c->stream->feed == c->stream)
1999
                src = c->stream->streams[i];
2000
            else
2001
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2002

    
2003
            *st = *src;
2004
            st->priv_data = 0;
2005
            st->codec->frame_number = 0; /* XXX: should be done in
2006
                                           AVStream, not in codec */
2007
            /* I'm pretty sure that this is not correct...
2008
             * However, without it, we crash
2009
             */
2010
            st->codec->coded_frame = &dummy_frame;
2011
        }
2012
        c->got_key_frame = 0;
2013

    
2014
        /* prepare header and save header data in a stream */
2015
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2016
            /* XXX: potential leak */
2017
            return -1;
2018
        }
2019
        c->fmt_ctx.pb.is_streamed = 1;
2020

    
2021
        av_set_parameters(&c->fmt_ctx, NULL);
2022
        if (av_write_header(&c->fmt_ctx) < 0)
2023
            return -1;
2024

    
2025
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2026
        c->buffer_ptr = c->pb_buffer;
2027
        c->buffer_end = c->pb_buffer + len;
2028

    
2029
        c->state = HTTPSTATE_SEND_DATA;
2030
        c->last_packet_sent = 0;
2031
        break;
2032
    case HTTPSTATE_SEND_DATA:
2033
        /* find a new packet */
2034
        {
2035
            AVPacket pkt;
2036

    
2037
            /* read a packet from the input stream */
2038
            if (c->stream->feed)
2039
                ffm_set_write_index(c->fmt_in,
2040
                                    c->stream->feed->feed_write_index,
2041
                                    c->stream->feed->feed_size);
2042

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

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

    
2143
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2144
                        if (c->is_packetized) {
2145
                            int max_packet_size;
2146
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2147
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2148
                            else
2149
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2150
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2151
                        } else {
2152
                            ret = url_open_dyn_buf(&ctx->pb);
2153
                        }
2154
                        if (ret < 0) {
2155
                            /* XXX: potential leak */
2156
                            return -1;
2157
                        }
2158
                        if (pkt.dts != AV_NOPTS_VALUE)
2159
                            pkt.dts = av_rescale_q(pkt.dts,
2160
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2161
                                ctx->streams[pkt.stream_index]->time_base);
2162
                        if (pkt.pts != AV_NOPTS_VALUE)
2163
                            pkt.pts = av_rescale_q(pkt.pts,
2164
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2165
                                ctx->streams[pkt.stream_index]->time_base);
2166
                        if (av_write_frame(ctx, &pkt))
2167
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2168

    
2169
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2170
                        c->cur_frame_bytes = len;
2171
                        c->buffer_ptr = c->pb_buffer;
2172
                        c->buffer_end = c->pb_buffer + len;
2173

    
2174
                        codec->frame_number++;
2175
                        if (len == 0)
2176
                            goto redo;
2177
                    }
2178
                    av_free_packet(&pkt);
2179
                }
2180
            }
2181
        }
2182
        break;
2183
    default:
2184
    case HTTPSTATE_SEND_DATA_TRAILER:
2185
        /* last packet test ? */
2186
        if (c->last_packet_sent || c->is_packetized)
2187
            return -1;
2188
        ctx = &c->fmt_ctx;
2189
        /* prepare header */
2190
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2191
            /* XXX: potential leak */
2192
            return -1;
2193
        }
2194
        av_write_trailer(ctx);
2195
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2196
        c->buffer_ptr = c->pb_buffer;
2197
        c->buffer_end = c->pb_buffer + len;
2198

    
2199
        c->last_packet_sent = 1;
2200
        break;
2201
    }
2202
    return 0;
2203
}
2204

    
2205
/* should convert the format at the same time */
2206
/* send data starting at c->buffer_ptr to the output connection
2207
   (either UDP or TCP connection) */
2208
static int http_send_data(HTTPContext *c)
2209
{
2210
    int len, ret;
2211

    
2212
    for(;;) {
2213
        if (c->buffer_ptr >= c->buffer_end) {
2214
            ret = http_prepare_data(c);
2215
            if (ret < 0)
2216
                return -1;
2217
            else if (ret != 0)
2218
                /* state change requested */
2219
                break;
2220
        } else {
2221
            if (c->is_packetized) {
2222
                /* RTP data output */
2223
                len = c->buffer_end - c->buffer_ptr;
2224
                if (len < 4) {
2225
                    /* fail safe - should never happen */
2226
                fail1:
2227
                    c->buffer_ptr = c->buffer_end;
2228
                    return 0;
2229
                }
2230
                len = (c->buffer_ptr[0] << 24) |
2231
                    (c->buffer_ptr[1] << 16) |
2232
                    (c->buffer_ptr[2] << 8) |
2233
                    (c->buffer_ptr[3]);
2234
                if (len > (c->buffer_end - c->buffer_ptr))
2235
                    goto fail1;
2236
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2237
                    /* nothing to send yet: we can wait */
2238
                    return 0;
2239
                }
2240

    
2241
                c->data_count += len;
2242
                update_datarate(&c->datarate, c->data_count);
2243
                if (c->stream)
2244
                    c->stream->bytes_served += len;
2245

    
2246
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2247
                    /* RTP packets are sent inside the RTSP TCP connection */
2248
                    ByteIOContext pb1, *pb = &pb1;
2249
                    int interleaved_index, size;
2250
                    uint8_t header[4];
2251
                    HTTPContext *rtsp_c;
2252

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

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

    
2316
                c->data_count += len;
2317
                update_datarate(&c->datarate, c->data_count);
2318
                if (c->stream)
2319
                    c->stream->bytes_served += len;
2320
                break;
2321
            }
2322
        }
2323
    } /* for(;;) */
2324
    return 0;
2325
}
2326

    
2327
static int http_start_receive_data(HTTPContext *c)
2328
{
2329
    int fd;
2330

    
2331
    if (c->stream->feed_opened)
2332
        return -1;
2333

    
2334
    /* Don't permit writing to this one */
2335
    if (c->stream->readonly)
2336
        return -1;
2337

    
2338
    /* open feed */
2339
    fd = open(c->stream->feed_filename, O_RDWR);
2340
    if (fd < 0)
2341
        return -1;
2342
    c->feed_fd = fd;
2343

    
2344
    c->stream->feed_write_index = ffm_read_write_index(fd);
2345
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2346
    lseek(fd, 0, SEEK_SET);
2347

    
2348
    /* init buffer input */
2349
    c->buffer_ptr = c->buffer;
2350
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2351
    c->stream->feed_opened = 1;
2352
    return 0;
2353
}
2354

    
2355
static int http_receive_data(HTTPContext *c)
2356
{
2357
    HTTPContext *c1;
2358

    
2359
    if (c->buffer_end > c->buffer_ptr) {
2360
        int len;
2361

    
2362
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2363
        if (len < 0) {
2364
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2365
                ff_neterrno() != FF_NETERROR(EINTR))
2366
                /* error : close connection */
2367
                goto fail;
2368
        } else if (len == 0)
2369
            /* end of connection : close it */
2370
            goto fail;
2371
        else {
2372
            c->buffer_ptr += len;
2373
            c->data_count += len;
2374
            update_datarate(&c->datarate, c->data_count);
2375
        }
2376
    }
2377

    
2378
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2379
        if (c->buffer[0] != 'f' ||
2380
            c->buffer[1] != 'm') {
2381
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2382
            goto fail;
2383
        }
2384
    }
2385

    
2386
    if (c->buffer_ptr >= c->buffer_end) {
2387
        FFStream *feed = c->stream;
2388
        /* a packet has been received : write it in the store, except
2389
           if header */
2390
        if (c->data_count > FFM_PACKET_SIZE) {
2391

    
2392
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2393
            /* XXX: use llseek or url_seek */
2394
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2395
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2396

    
2397
            feed->feed_write_index += FFM_PACKET_SIZE;
2398
            /* update file size */
2399
            if (feed->feed_write_index > c->stream->feed_size)
2400
                feed->feed_size = feed->feed_write_index;
2401

    
2402
            /* handle wrap around if max file size reached */
2403
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2404
                feed->feed_write_index = FFM_PACKET_SIZE;
2405

    
2406
            /* write index */
2407
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2408

    
2409
            /* wake up any waiting connections */
2410
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2411
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2412
                    c1->stream->feed == c->stream->feed)
2413
                    c1->state = HTTPSTATE_SEND_DATA;
2414
            }
2415
        } else {
2416
            /* We have a header in our hands that contains useful data */
2417
            AVFormatContext s;
2418
            AVInputFormat *fmt_in;
2419
            ByteIOContext *pb = &s.pb;
2420
            int i;
2421

    
2422
            memset(&s, 0, sizeof(s));
2423

    
2424
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2425
            pb->buf_end = c->buffer_end;        /* ?? */
2426
            pb->is_streamed = 1;
2427

    
2428
            /* use feed output format name to find corresponding input format */
2429
            fmt_in = av_find_input_format(feed->fmt->name);
2430
            if (!fmt_in)
2431
                goto fail;
2432

    
2433
            if (fmt_in->priv_data_size > 0) {
2434
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2435
                if (!s.priv_data)
2436
                    goto fail;
2437
            } else
2438
                s.priv_data = NULL;
2439

    
2440
            if (fmt_in->read_header(&s, 0) < 0) {
2441
                av_freep(&s.priv_data);
2442
                goto fail;
2443
            }
2444

    
2445
            /* Now we have the actual streams */
2446
            if (s.nb_streams != feed->nb_streams) {
2447
                av_freep(&s.priv_data);
2448
                goto fail;
2449
            }
2450
            for (i = 0; i < s.nb_streams; i++)
2451
                memcpy(feed->streams[i]->codec,
2452
                       s.streams[i]->codec, sizeof(AVCodecContext));
2453
            av_freep(&s.priv_data);
2454
        }
2455
        c->buffer_ptr = c->buffer;
2456
    }
2457

    
2458
    return 0;
2459
 fail:
2460
    c->stream->feed_opened = 0;
2461
    close(c->feed_fd);
2462
    return -1;
2463
}
2464

    
2465
/********************************************************************/
2466
/* RTSP handling */
2467

    
2468
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2469
{
2470
    const char *str;
2471
    time_t ti;
2472
    char *p;
2473
    char buf2[32];
2474

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

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

    
2517
    /* output GMT time */
2518
    ti = time(NULL);
2519
    p = ctime(&ti);
2520
    strcpy(buf2, p);
2521
    p = buf2 + strlen(p) - 1;
2522
    if (*p == '\n')
2523
        *p = '\0';
2524
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2525
}
2526

    
2527
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2528
{
2529
    rtsp_reply_header(c, error_number);
2530
    url_fprintf(c->pb, "\r\n");
2531
}
2532

    
2533
static int rtsp_parse_request(HTTPContext *c)
2534
{
2535
    const char *p, *p1, *p2;
2536
    char cmd[32];
2537
    char url[1024];
2538
    char protocol[32];
2539
    char line[1024];
2540
    ByteIOContext pb1;
2541
    int len;
2542
    RTSPHeader header1, *header = &header1;
2543

    
2544
    c->buffer_ptr[0] = '\0';
2545
    p = c->buffer;
2546

    
2547
    get_word(cmd, sizeof(cmd), &p);
2548
    get_word(url, sizeof(url), &p);
2549
    get_word(protocol, sizeof(protocol), &p);
2550

    
2551
    av_strlcpy(c->method, cmd, sizeof(c->method));
2552
    av_strlcpy(c->url, url, sizeof(c->url));
2553
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2554

    
2555
    c->pb = &pb1;
2556
    if (url_open_dyn_buf(c->pb) < 0) {
2557
        /* XXX: cannot do more */
2558
        c->pb = NULL; /* safety */
2559
        return -1;
2560
    }
2561

    
2562
    /* check version name */
2563
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2564
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2565
        goto the_end;
2566
    }
2567

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

    
2594
    /* handle sequence number */
2595
    c->seq = header->seq;
2596

    
2597
    if (!strcmp(cmd, "DESCRIBE"))
2598
        rtsp_cmd_describe(c, url);
2599
    else if (!strcmp(cmd, "OPTIONS"))
2600
        rtsp_cmd_options(c, url);
2601
    else if (!strcmp(cmd, "SETUP"))
2602
        rtsp_cmd_setup(c, url, header);
2603
    else if (!strcmp(cmd, "PLAY"))
2604
        rtsp_cmd_play(c, url, header);
2605
    else if (!strcmp(cmd, "PAUSE"))
2606
        rtsp_cmd_pause(c, url, header);
2607
    else if (!strcmp(cmd, "TEARDOWN"))
2608
        rtsp_cmd_teardown(c, url, header);
2609
    else
2610
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2611

    
2612
 the_end:
2613
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2614
    c->pb = NULL; /* safety */
2615
    if (len < 0) {
2616
        /* XXX: cannot do more */
2617
        return -1;
2618
    }
2619
    c->buffer_ptr = c->pb_buffer;
2620
    c->buffer_end = c->pb_buffer + len;
2621
    c->state = RTSPSTATE_SEND_REPLY;
2622
    return 0;
2623
}
2624

    
2625
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2626
   AVFormatContext */
2627
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2628
                                   struct in_addr my_ip)
2629
{
2630
    ByteIOContext pb1, *pb = &pb1;
2631
    int i, payload_type, port, private_payload_type, j;
2632
    const char *ipstr, *title, *mediatype;
2633
    AVStream *st;
2634

    
2635
    if (url_open_dyn_buf(pb) < 0)
2636
        return -1;
2637

    
2638
    /* general media info */
2639

    
2640
    url_fprintf(pb, "v=0\n");
2641
    ipstr = inet_ntoa(my_ip);
2642
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2643
    title = stream->title;
2644
    if (title[0] == '\0')
2645
        title = "No Title";
2646
    url_fprintf(pb, "s=%s\n", title);
2647
    if (stream->comment[0] != '\0')
2648
        url_fprintf(pb, "i=%s\n", stream->comment);
2649
    if (stream->is_multicast)
2650
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2651

    
2652
    /* for each stream, we output the necessary info */
2653
    private_payload_type = RTP_PT_PRIVATE;
2654
    for(i = 0; i < stream->nb_streams; i++) {
2655
        st = stream->streams[i];
2656
        if (st->codec->codec_id == CODEC_ID_MPEG2TS)
2657
            mediatype = "video";
2658
        else {
2659
            switch(st->codec->codec_type) {
2660
            case CODEC_TYPE_AUDIO:
2661
                mediatype = "audio";
2662
                break;
2663
            case CODEC_TYPE_VIDEO:
2664
                mediatype = "video";
2665
                break;
2666
            default:
2667
                mediatype = "application";
2668
                break;
2669
            }
2670
        }
2671
        /* NOTE: the port indication is not correct in case of
2672
           unicast. It is not an issue because RTSP gives it */
2673
        payload_type = rtp_get_payload_type(st->codec);
2674
        if (payload_type < 0)
2675
            payload_type = private_payload_type++;
2676
        if (stream->is_multicast)
2677
            port = stream->multicast_port + 2 * i;
2678
        else
2679
            port = 0;
2680

    
2681
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2682
                    mediatype, port, payload_type);
2683
        if (payload_type >= RTP_PT_PRIVATE) {
2684
            /* for private payload type, we need to give more info */
2685
            switch(st->codec->codec_id) {
2686
            case CODEC_ID_MPEG4:
2687
                {
2688
                    uint8_t *data;
2689
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2690
                                payload_type, 90000);
2691
                    /* we must also add the mpeg4 header */
2692
                    data = st->codec->extradata;
2693
                    if (data) {
2694
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2695
                        for(j=0;j<st->codec->extradata_size;j++)
2696
                            url_fprintf(pb, "%02x", data[j]);
2697
                        url_fprintf(pb, "\n");
2698
                    }
2699
                }
2700
                break;
2701
            default:
2702
                /* XXX: add other codecs ? */
2703
                goto fail;
2704
            }
2705
        }
2706
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2707
    }
2708
    return url_close_dyn_buf(pb, pbuffer);
2709
 fail:
2710
    url_close_dyn_buf(pb, pbuffer);
2711
    av_free(*pbuffer);
2712
    return -1;
2713
}
2714

    
2715
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2716
{
2717
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2718
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2719
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2720
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2721
    url_fprintf(c->pb, "\r\n");
2722
}
2723

    
2724
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2725
{
2726
    FFStream *stream;
2727
    char path1[1024];
2728
    const char *path;
2729
    uint8_t *content;
2730
    int content_length, len;
2731
    struct sockaddr_in my_addr;
2732

    
2733
    /* find which url is asked */
2734
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2735
    path = path1;
2736
    if (*path == '/')
2737
        path++;
2738

    
2739
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2740
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2741
            !strcmp(path, stream->filename)) {
2742
            goto found;
2743
        }
2744
    }
2745
    /* no stream found */
2746
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2747
    return;
2748

    
2749
 found:
2750
    /* prepare the media description in sdp format */
2751

    
2752
    /* get the host IP */
2753
    len = sizeof(my_addr);
2754
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2755
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2756
    if (content_length < 0) {
2757
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2758
        return;
2759
    }
2760
    rtsp_reply_header(c, RTSP_STATUS_OK);
2761
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2762
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2763
    url_fprintf(c->pb, "\r\n");
2764
    put_buffer(c->pb, content, content_length);
2765
}
2766

    
2767
static HTTPContext *find_rtp_session(const char *session_id)
2768
{
2769
    HTTPContext *c;
2770

    
2771
    if (session_id[0] == '\0')
2772
        return NULL;
2773

    
2774
    for(c = first_http_ctx; c != NULL; c = c->next) {
2775
        if (!strcmp(c->session_id, session_id))
2776
            return c;
2777
    }
2778
    return NULL;
2779
}
2780

    
2781
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2782
{
2783
    RTSPTransportField *th;
2784
    int i;
2785

    
2786
    for(i=0;i<h->nb_transports;i++) {
2787
        th = &h->transports[i];
2788
        if (th->protocol == protocol)
2789
            return th;
2790
    }
2791
    return NULL;
2792
}
2793

    
2794
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2795
                           RTSPHeader *h)
2796
{
2797
    FFStream *stream;
2798
    int stream_index, port;
2799
    char buf[1024];
2800
    char path1[1024];
2801
    const char *path;
2802
    HTTPContext *rtp_c;
2803
    RTSPTransportField *th;
2804
    struct sockaddr_in dest_addr;
2805
    RTSPActionServerSetup setup;
2806

    
2807
    /* find which url is asked */
2808
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2809
    path = path1;
2810
    if (*path == '/')
2811
        path++;
2812

    
2813
    /* now check each stream */
2814
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2815
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2816
            /* accept aggregate filenames only if single stream */
2817
            if (!strcmp(path, stream->filename)) {
2818
                if (stream->nb_streams != 1) {
2819
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2820
                    return;
2821
                }
2822
                stream_index = 0;
2823
                goto found;
2824
            }
2825

    
2826
            for(stream_index = 0; stream_index < stream->nb_streams;
2827
                stream_index++) {
2828
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2829
                         stream->filename, stream_index);
2830
                if (!strcmp(path, buf))
2831
                    goto found;
2832
            }
2833
        }
2834
    }
2835
    /* no stream found */
2836
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2837
    return;
2838
 found:
2839

    
2840
    /* generate session id if needed */
2841
    if (h->session_id[0] == '\0')
2842
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2843
                 av_random(&random_state), av_random(&random_state));
2844

    
2845
    /* find rtp session, and create it if none found */
2846
    rtp_c = find_rtp_session(h->session_id);
2847
    if (!rtp_c) {
2848
        /* always prefer UDP */
2849
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2850
        if (!th) {
2851
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2852
            if (!th) {
2853
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2854
                return;
2855
            }
2856
        }
2857

    
2858
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2859
                                   th->protocol);
2860
        if (!rtp_c) {
2861
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2862
            return;
2863
        }
2864

    
2865
        /* open input stream */
2866
        if (open_input_stream(rtp_c, "") < 0) {
2867
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2868
            return;
2869
        }
2870
    }
2871

    
2872
    /* test if stream is OK (test needed because several SETUP needs
2873
       to be done for a given file) */
2874
    if (rtp_c->stream != stream) {
2875
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2876
        return;
2877
    }
2878

    
2879
    /* test if stream is already set up */
2880
    if (rtp_c->rtp_ctx[stream_index]) {
2881
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2882
        return;
2883
    }
2884

    
2885
    /* check transport */
2886
    th = find_transport(h, rtp_c->rtp_protocol);
2887
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2888
                th->client_port_min <= 0)) {
2889
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2890
        return;
2891
    }
2892

    
2893
    /* setup default options */
2894
    setup.transport_option[0] = '\0';
2895
    dest_addr = rtp_c->from_addr;
2896
    dest_addr.sin_port = htons(th->client_port_min);
2897

    
2898
    /* setup stream */
2899
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2900
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2901
        return;
2902
    }
2903

    
2904
    /* now everything is OK, so we can send the connection parameters */
2905
    rtsp_reply_header(c, RTSP_STATUS_OK);
2906
    /* session ID */
2907
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2908

    
2909
    switch(rtp_c->rtp_protocol) {
2910
    case RTSP_PROTOCOL_RTP_UDP:
2911
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2912
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2913
                    "client_port=%d-%d;server_port=%d-%d",
2914
                    th->client_port_min, th->client_port_min + 1,
2915
                    port, port + 1);
2916
        break;
2917
    case RTSP_PROTOCOL_RTP_TCP:
2918
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2919
                    stream_index * 2, stream_index * 2 + 1);
2920
        break;
2921
    default:
2922
        break;
2923
    }
2924
    if (setup.transport_option[0] != '\0')
2925
        url_fprintf(c->pb, ";%s", setup.transport_option);
2926
    url_fprintf(c->pb, "\r\n");
2927

    
2928

    
2929
    url_fprintf(c->pb, "\r\n");
2930
}
2931

    
2932

    
2933
/* find an rtp connection by using the session ID. Check consistency
2934
   with filename */
2935
static HTTPContext *find_rtp_session_with_url(const char *url,
2936
                                              const char *session_id)
2937
{
2938
    HTTPContext *rtp_c;
2939
    char path1[1024];
2940
    const char *path;
2941
    char buf[1024];
2942
    int s;
2943

    
2944
    rtp_c = find_rtp_session(session_id);
2945
    if (!rtp_c)
2946
        return NULL;
2947

    
2948
    /* find which url is asked */
2949
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2950
    path = path1;
2951
    if (*path == '/')
2952
        path++;
2953
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2954
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2955
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2956
        rtp_c->stream->filename, s);
2957
      if(!strncmp(path, buf, sizeof(buf))) {
2958
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2959
        return rtp_c;
2960
      }
2961
    }
2962
    return NULL;
2963
}
2964

    
2965
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2966
{
2967
    HTTPContext *rtp_c;
2968

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

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

    
2982
#if 0
2983
    /* XXX: seek in stream */
2984
    if (h->range_start != AV_NOPTS_VALUE) {
2985
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2986
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2987
    }
2988
#endif
2989

    
2990
    rtp_c->state = HTTPSTATE_SEND_DATA;
2991

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

    
2999
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3000
{
3001
    HTTPContext *rtp_c;
3002

    
3003
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3004
    if (!rtp_c) {
3005
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3006
        return;
3007
    }
3008

    
3009
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3010
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3011
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3012
        return;
3013
    }
3014

    
3015
    rtp_c->state = HTTPSTATE_READY;
3016
    rtp_c->first_pts = AV_NOPTS_VALUE;
3017
    /* now everything is OK, so we can send the connection parameters */
3018
    rtsp_reply_header(c, RTSP_STATUS_OK);
3019
    /* session ID */
3020
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3021
    url_fprintf(c->pb, "\r\n");
3022
}
3023

    
3024
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3025
{
3026
    HTTPContext *rtp_c;
3027
    char session_id[32];
3028

    
3029
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3030
    if (!rtp_c) {
3031
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3032
        return;
3033
    }
3034

    
3035
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3036

    
3037
    /* abort the session */
3038
    close_connection(rtp_c);
3039

    
3040
    /* now everything is OK, so we can send the connection parameters */
3041
    rtsp_reply_header(c, RTSP_STATUS_OK);
3042
    /* session ID */
3043
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3044
    url_fprintf(c->pb, "\r\n");
3045
}
3046

    
3047

    
3048
/********************************************************************/
3049
/* RTP handling */
3050

    
3051
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3052
                                       FFStream *stream, const char *session_id,
3053
                                       enum RTSPProtocol rtp_protocol)
3054
{
3055
    HTTPContext *c = NULL;
3056
    const char *proto_str;
3057

    
3058
    /* XXX: should output a warning page when coming
3059
       close to the connection limit */
3060
    if (nb_connections >= nb_max_connections)
3061
        goto fail;
3062

    
3063
    /* add a new connection */
3064
    c = av_mallocz(sizeof(HTTPContext));
3065
    if (!c)
3066
        goto fail;
3067

    
3068
    c->fd = -1;
3069
    c->poll_entry = NULL;
3070
    c->from_addr = *from_addr;
3071
    c->buffer_size = IOBUFFER_INIT_SIZE;
3072
    c->buffer = av_malloc(c->buffer_size);
3073
    if (!c->buffer)
3074
        goto fail;
3075
    nb_connections++;
3076
    c->stream = stream;
3077
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3078
    c->state = HTTPSTATE_READY;
3079
    c->is_packetized = 1;
3080
    c->rtp_protocol = rtp_protocol;
3081

    
3082
    /* protocol is shown in statistics */
3083
    switch(c->rtp_protocol) {
3084
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3085
        proto_str = "MCAST";
3086
        break;
3087
    case RTSP_PROTOCOL_RTP_UDP:
3088
        proto_str = "UDP";
3089
        break;
3090
    case RTSP_PROTOCOL_RTP_TCP:
3091
        proto_str = "TCP";
3092
        break;
3093
    default:
3094
        proto_str = "???";
3095
        break;
3096
    }
3097
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3098
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3099

    
3100
    current_bandwidth += stream->bandwidth;
3101

    
3102
    c->next = first_http_ctx;
3103
    first_http_ctx = c;
3104
    return c;
3105

    
3106
 fail:
3107
    if (c) {
3108
        av_free(c->buffer);
3109
        av_free(c);
3110
    }
3111
    return NULL;
3112
}
3113

    
3114
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3115
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3116
   used. */
3117
static int rtp_new_av_stream(HTTPContext *c,
3118
                             int stream_index, struct sockaddr_in *dest_addr,
3119
                             HTTPContext *rtsp_c)
3120
{
3121
    AVFormatContext *ctx;
3122
    AVStream *st;
3123
    char *ipaddr;
3124
    URLContext *h;
3125
    uint8_t *dummy_buf;
3126
    char buf2[32];
3127
    int max_packet_size;
3128

    
3129
    /* now we can open the relevant output stream */
3130
    ctx = av_alloc_format_context();
3131
    if (!ctx)
3132
        return -1;
3133
    ctx->oformat = &rtp_muxer;
3134

    
3135
    st = av_mallocz(sizeof(AVStream));
3136
    if (!st)
3137
        goto fail;
3138
    st->codec= avcodec_alloc_context();
3139
    ctx->nb_streams = 1;
3140
    ctx->streams[0] = st;
3141

    
3142
    if (!c->stream->feed ||
3143
        c->stream->feed == c->stream)
3144
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3145
    else
3146
        memcpy(st,
3147
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3148
               sizeof(AVStream));
3149
    st->priv_data = NULL;
3150

    
3151
    /* build destination RTP address */
3152
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3153

    
3154
    switch(c->rtp_protocol) {
3155
    case RTSP_PROTOCOL_RTP_UDP:
3156
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3157
        /* RTP/UDP case */
3158

    
3159
        /* XXX: also pass as parameter to function ? */
3160
        if (c->stream->is_multicast) {
3161
            int ttl;
3162
            ttl = c->stream->multicast_ttl;
3163
            if (!ttl)
3164
                ttl = 16;
3165
            snprintf(ctx->filename, sizeof(ctx->filename),
3166
                     "rtp://%s:%d?multicast=1&ttl=%d",
3167
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3168
        } else {
3169
            snprintf(ctx->filename, sizeof(ctx->filename),
3170
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3171
        }
3172

    
3173
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3174
            goto fail;
3175
        c->rtp_handles[stream_index] = h;
3176
        max_packet_size = url_get_max_packet_size(h);
3177
        break;
3178
    case RTSP_PROTOCOL_RTP_TCP:
3179
        /* RTP/TCP case */
3180
        c->rtsp_c = rtsp_c;
3181
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3182
        break;
3183
    default:
3184
        goto fail;
3185
    }
3186

    
3187
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3188
             ipaddr, ntohs(dest_addr->sin_port),
3189
             ctime1(buf2),
3190
             c->stream->filename, stream_index, c->protocol);
3191

    
3192
    /* normally, no packets should be output here, but the packet size may be checked */
3193
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3194
        /* XXX: close stream */
3195
        goto fail;
3196
    }
3197
    av_set_parameters(ctx, NULL);
3198
    if (av_write_header(ctx) < 0) {
3199
    fail:
3200
        if (h)
3201
            url_close(h);
3202
        av_free(ctx);
3203
        return -1;
3204
    }
3205
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3206
    av_free(dummy_buf);
3207

    
3208
    c->rtp_ctx[stream_index] = ctx;
3209
    return 0;
3210
}
3211

    
3212
/********************************************************************/
3213
/* ffserver initialization */
3214

    
3215
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3216
{
3217
    AVStream *fst;
3218

    
3219
    fst = av_mallocz(sizeof(AVStream));
3220
    if (!fst)
3221
        return NULL;
3222
    fst->codec= avcodec_alloc_context();
3223
    fst->priv_data = av_mallocz(sizeof(FeedData));
3224
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3225
    fst->codec->coded_frame = &dummy_frame;
3226
    fst->index = stream->nb_streams;
3227
    av_set_pts_info(fst, 33, 1, 90000);
3228
    stream->streams[stream->nb_streams++] = fst;
3229
    return fst;
3230
}
3231

    
3232
/* return the stream number in the feed */
3233
static int add_av_stream(FFStream *feed, AVStream *st)
3234
{
3235
    AVStream *fst;
3236
    AVCodecContext *av, *av1;
3237
    int i;
3238

    
3239
    av = st->codec;
3240
    for(i=0;i<feed->nb_streams;i++) {
3241
        st = feed->streams[i];
3242
        av1 = st->codec;
3243
        if (av1->codec_id == av->codec_id &&
3244
            av1->codec_type == av->codec_type &&
3245
            av1->bit_rate == av->bit_rate) {
3246

    
3247
            switch(av->codec_type) {
3248
            case CODEC_TYPE_AUDIO:
3249
                if (av1->channels == av->channels &&
3250
                    av1->sample_rate == av->sample_rate)
3251
                    goto found;
3252
                break;
3253
            case CODEC_TYPE_VIDEO:
3254
                if (av1->width == av->width &&
3255
                    av1->height == av->height &&
3256
                    av1->time_base.den == av->time_base.den &&
3257
                    av1->time_base.num == av->time_base.num &&
3258
                    av1->gop_size == av->gop_size)
3259
                    goto found;
3260
                break;
3261
            default:
3262
                abort();
3263
            }
3264
        }
3265
    }
3266

    
3267
    fst = add_av_stream1(feed, av);
3268
    if (!fst)
3269
        return -1;
3270
    return feed->nb_streams - 1;
3271
 found:
3272
    return i;
3273
}
3274

    
3275
static void remove_stream(FFStream *stream)
3276
{
3277
    FFStream **ps;
3278
    ps = &first_stream;
3279
    while (*ps != NULL) {
3280
        if (*ps == stream)
3281
            *ps = (*ps)->next;
3282
        else
3283
            ps = &(*ps)->next;
3284
    }
3285
}
3286

    
3287
/* specific mpeg4 handling : we extract the raw parameters */
3288
static void extract_mpeg4_header(AVFormatContext *infile)
3289
{
3290
    int mpeg4_count, i, size;
3291
    AVPacket pkt;
3292
    AVStream *st;
3293
    const uint8_t *p;
3294

    
3295
    mpeg4_count = 0;
3296
    for(i=0;i<infile->nb_streams;i++) {
3297
        st = infile->streams[i];
3298
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3299
            st->codec->extradata_size == 0) {
3300
            mpeg4_count++;
3301
        }
3302
    }
3303
    if (!mpeg4_count)
3304
        return;
3305

    
3306
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3307
    while (mpeg4_count > 0) {
3308
        if (av_read_packet(infile, &pkt) < 0)
3309
            break;
3310
        st = infile->streams[pkt.stream_index];
3311
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3312
            st->codec->extradata_size == 0) {
3313
            av_freep(&st->codec->extradata);
3314
            /* fill extradata with the header */
3315
            /* XXX: we make hard suppositions here ! */
3316
            p = pkt.data;
3317
            while (p < pkt.data + pkt.size - 4) {
3318
                /* stop when vop header is found */
3319
                if (p[0] == 0x00 && p[1] == 0x00 &&
3320
                    p[2] == 0x01 && p[3] == 0xb6) {
3321
                    size = p - pkt.data;
3322
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3323
                    st->codec->extradata = av_malloc(size);
3324
                    st->codec->extradata_size = size;
3325
                    memcpy(st->codec->extradata, pkt.data, size);
3326
                    break;
3327
                }
3328
                p++;
3329
            }
3330
            mpeg4_count--;
3331
        }
3332
        av_free_packet(&pkt);
3333
    }
3334
}
3335

    
3336
/* compute the needed AVStream for each file */
3337
static void build_file_streams(void)
3338
{
3339
    FFStream *stream, *stream_next;
3340
    AVFormatContext *infile;
3341
    int i;
3342

    
3343
    /* gather all streams */
3344
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3345
        stream_next = stream->next;
3346
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3347
            !stream->feed) {
3348
            /* the stream comes from a file */
3349
            /* try to open the file */
3350
            /* open stream */
3351
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3352
            if (stream->fmt == &rtp_muxer) {
3353
                /* specific case : if transport stream output to RTP,
3354
                   we use a raw transport stream reader */
3355
                stream->ap_in->mpeg2ts_raw = 1;
3356
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3357
            }
3358

    
3359
            if (av_open_input_file(&infile, stream->feed_filename,
3360
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3361
                http_log("%s not found", stream->feed_filename);
3362
                /* remove stream (no need to spend more time on it) */
3363
            fail:
3364
                remove_stream(stream);
3365
            } else {
3366
                /* find all the AVStreams inside and reference them in
3367
                   'stream' */
3368
                if (av_find_stream_info(infile) < 0) {
3369
                    http_log("Could not find codec parameters from '%s'",
3370
                             stream->feed_filename);
3371
                    av_close_input_file(infile);
3372
                    goto fail;
3373
                }
3374
                extract_mpeg4_header(infile);
3375

    
3376
                for(i=0;i<infile->nb_streams;i++)
3377
                    add_av_stream1(stream, infile->streams[i]->codec);
3378

    
3379
                av_close_input_file(infile);
3380
            }
3381
        }
3382
    }
3383
}
3384

    
3385
/* compute the needed AVStream for each feed */
3386
static void build_feed_streams(void)
3387
{
3388
    FFStream *stream, *feed;
3389
    int i;
3390

    
3391
    /* gather all streams */
3392
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3393
        feed = stream->feed;
3394
        if (feed) {
3395
            if (!stream->is_feed) {
3396
                /* we handle a stream coming from a feed */
3397
                for(i=0;i<stream->nb_streams;i++)
3398
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3399
            }
3400
        }
3401
    }
3402

    
3403
    /* gather all streams */
3404
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3405
        feed = stream->feed;
3406
        if (feed) {
3407
            if (stream->is_feed) {
3408
                for(i=0;i<stream->nb_streams;i++)
3409
                    stream->feed_streams[i] = i;
3410
            }
3411
        }
3412
    }
3413

    
3414
    /* create feed files if needed */
3415
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3416
        int fd;
3417

    
3418
        if (url_exist(feed->feed_filename)) {
3419
            /* See if it matches */
3420
            AVFormatContext *s;
3421
            int matches = 0;
3422

    
3423
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3424
                /* Now see if it matches */
3425
                if (s->nb_streams == feed->nb_streams) {
3426
                    matches = 1;
3427
                    for(i=0;i<s->nb_streams;i++) {
3428
                        AVStream *sf, *ss;
3429
                        sf = feed->streams[i];
3430
                        ss = s->streams[i];
3431

    
3432
                        if (sf->index != ss->index ||
3433
                            sf->id != ss->id) {
3434
                            printf("Index & Id do not match for stream %d (%s)\n",
3435
                                   i, feed->feed_filename);
3436
                            matches = 0;
3437
                        } else {
3438
                            AVCodecContext *ccf, *ccs;
3439

    
3440
                            ccf = sf->codec;
3441
                            ccs = ss->codec;
3442
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3443

    
3444
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3445
                                printf("Codecs do not match for stream %d\n", i);
3446
                                matches = 0;
3447
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3448
                                printf("Codec bitrates do not match for stream %d\n", i);
3449
                                matches = 0;
3450
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3451
                                if (CHECK_CODEC(time_base.den) ||
3452
                                    CHECK_CODEC(time_base.num) ||
3453
                                    CHECK_CODEC(width) ||
3454
                                    CHECK_CODEC(height)) {
3455
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3456
                                    matches = 0;
3457
                                }
3458
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3459
                                if (CHECK_CODEC(sample_rate) ||
3460
                                    CHECK_CODEC(channels) ||
3461
                                    CHECK_CODEC(frame_size)) {
3462
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3463
                                    matches = 0;
3464
                                }
3465
                            } else {
3466
                                printf("Unknown codec type\n");
3467
                                matches = 0;
3468
                            }
3469
                        }
3470
                        if (!matches)
3471
                            break;
3472
                    }
3473
                } else
3474
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3475
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3476

    
3477
                av_close_input_file(s);
3478
            } else
3479
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3480
                        feed->feed_filename);
3481

    
3482
            if (!matches) {
3483
                if (feed->readonly) {
3484
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3485
                        feed->feed_filename);
3486
                    exit(1);
3487
                }
3488
                unlink(feed->feed_filename);
3489
            }
3490
        }
3491
        if (!url_exist(feed->feed_filename)) {
3492
            AVFormatContext s1, *s = &s1;
3493

    
3494
            if (feed->readonly) {
3495
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3496
                    feed->feed_filename);
3497
                exit(1);
3498
            }
3499

    
3500
            /* only write the header of the ffm file */
3501
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3502
                fprintf(stderr, "Could not open output feed file '%s'\n",
3503
                        feed->feed_filename);
3504
                exit(1);
3505
            }
3506
            s->oformat = feed->fmt;
3507
            s->nb_streams = feed->nb_streams;
3508
            for(i=0;i<s->nb_streams;i++) {
3509
                AVStream *st;
3510
                st = feed->streams[i];
3511
                s->streams[i] = st;
3512
            }
3513
            av_set_parameters(s, NULL);
3514
            if (av_write_header(s) < 0) {
3515
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3516
                exit(1);
3517
            }
3518
            /* XXX: need better api */
3519
            av_freep(&s->priv_data);
3520
            url_fclose(&s->pb);
3521
        }
3522
        /* get feed size and write index */
3523
        fd = open(feed->feed_filename, O_RDONLY);
3524
        if (fd < 0) {
3525
            fprintf(stderr, "Could not open output feed file '%s'\n",
3526
                    feed->feed_filename);
3527
            exit(1);
3528
        }
3529

    
3530
        feed->feed_write_index = ffm_read_write_index(fd);
3531
        feed->feed_size = lseek(fd, 0, SEEK_END);
3532
        /* ensure that we do not wrap before the end of file */
3533
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3534
            feed->feed_max_size = feed->feed_size;
3535

    
3536
        close(fd);
3537
    }
3538
}
3539

    
3540
/* compute the bandwidth used by each stream */
3541
static void compute_bandwidth(void)
3542
{
3543
    int bandwidth, i;
3544
    FFStream *stream;
3545

    
3546
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3547
        bandwidth = 0;
3548
        for(i=0;i<stream->nb_streams;i++) {
3549
            AVStream *st = stream->streams[i];
3550
            switch(st->codec->codec_type) {
3551
            case CODEC_TYPE_AUDIO:
3552
            case CODEC_TYPE_VIDEO:
3553
                bandwidth += st->codec->bit_rate;
3554
                break;
3555
            default:
3556
                break;
3557
            }
3558
        }
3559
        stream->bandwidth = (bandwidth + 999) / 1000;
3560
    }
3561
}
3562

    
3563
static void get_arg(char *buf, int buf_size, const char **pp)
3564
{
3565
    const char *p;
3566
    char *q;
3567
    int quote;
3568

    
3569
    p = *pp;
3570
    while (isspace(*p)) p++;
3571
    q = buf;
3572
    quote = 0;
3573
    if (*p == '\"' || *p == '\'')
3574
        quote = *p++;
3575
    for(;;) {
3576
        if (quote) {
3577
            if (*p == quote)
3578
                break;
3579
        } else {
3580
            if (isspace(*p))
3581
                break;
3582
        }
3583
        if (*p == '\0')
3584
            break;
3585
        if ((q - buf) < buf_size - 1)
3586
            *q++ = *p;
3587
        p++;
3588
    }
3589
    *q = '\0';
3590
    if (quote && *p == quote)
3591
        p++;
3592
    *pp = p;
3593
}
3594

    
3595
/* add a codec and set the default parameters */
3596
static void add_codec(FFStream *stream, AVCodecContext *av)
3597
{
3598
    AVStream *st;
3599

    
3600
    /* compute default parameters */
3601
    switch(av->codec_type) {
3602
    case CODEC_TYPE_AUDIO:
3603
        if (av->bit_rate == 0)
3604
            av->bit_rate = 64000;
3605
        if (av->sample_rate == 0)
3606
            av->sample_rate = 22050;
3607
        if (av->channels == 0)
3608
            av->channels = 1;
3609
        break;
3610
    case CODEC_TYPE_VIDEO:
3611
        if (av->bit_rate == 0)
3612
            av->bit_rate = 64000;
3613
        if (av->time_base.num == 0){
3614
            av->time_base.den = 5;
3615
            av->time_base.num = 1;
3616
        }
3617
        if (av->width == 0 || av->height == 0) {
3618
            av->width = 160;
3619
            av->height = 128;
3620
        }
3621
        /* Bitrate tolerance is less for streaming */
3622
        if (av->bit_rate_tolerance == 0)
3623
            av->bit_rate_tolerance = av->bit_rate / 4;
3624
        if (av->qmin == 0)
3625
            av->qmin = 3;
3626
        if (av->qmax == 0)
3627
            av->qmax = 31;
3628
        if (av->max_qdiff == 0)
3629
            av->max_qdiff = 3;
3630
        av->qcompress = 0.5;
3631
        av->qblur = 0.5;
3632

    
3633
        if (!av->nsse_weight)
3634
            av->nsse_weight = 8;
3635

    
3636
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3637
        av->me_method = ME_EPZS;
3638
        av->rc_buffer_aggressivity = 1.0;
3639

    
3640
        if (!av->rc_eq)
3641
            av->rc_eq = "tex^qComp";
3642
        if (!av->i_quant_factor)
3643
            av->i_quant_factor = -0.8;
3644
        if (!av->b_quant_factor)
3645
            av->b_quant_factor = 1.25;
3646
        if (!av->b_quant_offset)
3647
            av->b_quant_offset = 1.25;
3648
        if (!av->rc_max_rate)
3649
            av->rc_max_rate = av->bit_rate * 2;
3650

    
3651
        if (av->rc_max_rate && !av->rc_buffer_size) {
3652
            av->rc_buffer_size = av->rc_max_rate;
3653
        }
3654

    
3655

    
3656
        break;
3657
    default:
3658
        abort();
3659
    }
3660

    
3661
    st = av_mallocz(sizeof(AVStream));
3662
    if (!st)
3663
        return;
3664
    st->codec = avcodec_alloc_context();
3665
    stream->streams[stream->nb_streams++] = st;
3666
    memcpy(st->codec, av, sizeof(AVCodecContext));
3667
}
3668

    
3669
static int opt_audio_codec(const char *arg)
3670
{
3671
    AVCodec *p;
3672

    
3673
    p = first_avcodec;
3674
    while (p) {
3675
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3676
            break;
3677
        p = p->next;
3678
    }
3679
    if (p == NULL)
3680
        return CODEC_ID_NONE;
3681

    
3682
    return p->id;
3683
}
3684

    
3685
static int opt_video_codec(const char *arg)
3686
{
3687
    AVCodec *p;
3688

    
3689
    p = first_avcodec;
3690
    while (p) {
3691
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3692
            break;
3693
        p = p->next;
3694
    }
3695
    if (p == NULL)
3696
        return CODEC_ID_NONE;
3697

    
3698
    return p->id;
3699
}
3700

    
3701
/* simplistic plugin support */
3702

    
3703
#ifdef HAVE_DLOPEN
3704
static void load_module(const char *filename)
3705
{
3706
    void *dll;
3707
    void (*init_func)(void);
3708
    dll = dlopen(filename, RTLD_NOW);
3709
    if (!dll) {
3710
        fprintf(stderr, "Could not load module '%s' - %s\n",
3711
                filename, dlerror());
3712
        return;
3713
    }
3714

    
3715
    init_func = dlsym(dll, "ffserver_module_init");
3716
    if (!init_func) {
3717
        fprintf(stderr,
3718
                "%s: init function 'ffserver_module_init()' not found\n",
3719
                filename);
3720
        dlclose(dll);
3721
    }
3722

    
3723
    init_func();
3724
}
3725
#endif
3726

    
3727
static int parse_ffconfig(const char *filename)
3728
{
3729
    FILE *f;
3730
    char line[1024];
3731
    char cmd[64];
3732
    char arg[1024];
3733
    const char *p;
3734
    int val, errors, line_num;
3735
    FFStream **last_stream, *stream, *redirect;
3736
    FFStream **last_feed, *feed;
3737
    AVCodecContext audio_enc, video_enc;
3738
    int audio_id, video_id;
3739

    
3740
    f = fopen(filename, "r");
3741
    if (!f) {
3742
        perror(filename);
3743
        return -1;
3744
    }
3745

    
3746
    errors = 0;
3747
    line_num = 0;
3748
    first_stream = NULL;
3749
    last_stream = &first_stream;
3750
    first_feed = NULL;
3751
    last_feed = &first_feed;
3752
    stream = NULL;
3753
    feed = NULL;
3754
    redirect = NULL;
3755
    audio_id = CODEC_ID_NONE;
3756
    video_id = CODEC_ID_NONE;
3757
    for(;;) {
3758
        if (fgets(line, sizeof(line), f) == NULL)
3759
            break;
3760
        line_num++;
3761
        p = line;
3762
        while (isspace(*p))
3763
            p++;
3764
        if (*p == '\0' || *p == '#')
3765
            continue;
3766

    
3767
        get_arg(cmd, sizeof(cmd), &p);
3768

    
3769
        if (!strcasecmp(cmd, "Port")) {
3770
            get_arg(arg, sizeof(arg), &p);
3771
            val = atoi(arg);
3772
            if (val < 1 || val > 65536) {
3773
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3774
                        filename, line_num, arg);
3775
                errors++;
3776
            }
3777
            my_http_addr.sin_port = htons(val);
3778
        } else if (!strcasecmp(cmd, "BindAddress")) {
3779
            get_arg(arg, sizeof(arg), &p);
3780
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3781
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3782
                        filename, line_num, arg);
3783
                errors++;
3784
            }
3785
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3786
            ffserver_daemon = 0;
3787
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3788
            get_arg(arg, sizeof(arg), &p);
3789
            val = atoi(arg);
3790
            if (val < 1 || val > 65536) {
3791
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3792
                        filename, line_num, arg);
3793
                errors++;
3794
            }
3795
            my_rtsp_addr.sin_port = htons(atoi(arg));
3796
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3797
            get_arg(arg, sizeof(arg), &p);
3798
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3799
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3800
                        filename, line_num, arg);
3801
                errors++;
3802
            }
3803
        } else if (!strcasecmp(cmd, "MaxClients")) {
3804
            get_arg(arg, sizeof(arg), &p);
3805
            val = atoi(arg);
3806
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3807
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3808
                        filename, line_num, arg);
3809
                errors++;
3810
            } else {
3811
                nb_max_connections = val;
3812
            }
3813
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3814
            get_arg(arg, sizeof(arg), &p);
3815
            val = atoi(arg);
3816
            if (val < 10 || val > 100000) {
3817
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3818
                        filename, line_num, arg);
3819
                errors++;
3820
            } else
3821
                max_bandwidth = val;
3822
        } else if (!strcasecmp(cmd, "CustomLog")) {
3823
            get_arg(logfilename, sizeof(logfilename), &p);
3824
        } else if (!strcasecmp(cmd, "<Feed")) {
3825
            /*********************************************/
3826
            /* Feed related options */
3827
            char *q;
3828
            if (stream || feed) {
3829
                fprintf(stderr, "%s:%d: Already in a tag\n",
3830
                        filename, line_num);
3831
            } else {
3832
                feed = av_mallocz(sizeof(FFStream));
3833
                /* add in stream list */
3834
                *last_stream = feed;
3835
                last_stream = &feed->next;
3836
                /* add in feed list */
3837
                *last_feed = feed;
3838
                last_feed = &feed->next_feed;
3839

    
3840
                get_arg(feed->filename, sizeof(feed->filename), &p);
3841
                q = strrchr(feed->filename, '>');
3842
                if (*q)
3843
                    *q = '\0';
3844
                feed->fmt = guess_format("ffm", NULL, NULL);
3845
                /* defaut feed file */
3846
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3847
                         "/tmp/%s.ffm", feed->filename);
3848
                feed->feed_max_size = 5 * 1024 * 1024;
3849
                feed->is_feed = 1;
3850
                feed->feed = feed; /* self feeding :-) */
3851
            }
3852
        } else if (!strcasecmp(cmd, "Launch")) {
3853
            if (feed) {
3854
                int i;
3855

    
3856
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3857

    
3858
                for (i = 0; i < 62; i++) {
3859
                    get_arg(arg, sizeof(arg), &p);
3860
                    if (!arg[0])
3861
                        break;
3862

    
3863
                    feed->child_argv[i] = av_strdup(arg);
3864
                }
3865

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

    
3868
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3869
                    "http://%s:%d/%s",
3870
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3871
                    inet_ntoa(my_http_addr.sin_addr),
3872
                    ntohs(my_http_addr.sin_port), feed->filename);
3873

    
3874
                if (ffserver_debug)
3875
                {
3876
                    int j;
3877
                    fprintf(stdout, "Launch commandline: ");
3878
                    for (j = 0; j <= i; j++)
3879
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3880
                    fprintf(stdout, "\n");
3881
                }
3882
            }
3883
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3884
            if (feed) {
3885
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3886
                feed->readonly = 1;
3887
            } else if (stream) {
3888
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3889
            }
3890
        } else if (!strcasecmp(cmd, "File")) {
3891
            if (feed) {
3892
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3893
            } else if (stream)
3894
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3895
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3896
            if (feed) {
3897
                const char *p1;
3898
                double fsize;
3899

    
3900
                get_arg(arg, sizeof(arg), &p);
3901
                p1 = arg;
3902
                fsize = strtod(p1, (char **)&p1);
3903
                switch(toupper(*p1)) {
3904
                case 'K':
3905
                    fsize *= 1024;
3906
                    break;
3907
                case 'M':
3908
                    fsize *= 1024 * 1024;
3909
                    break;
3910
                case 'G':
3911
                    fsize *= 1024 * 1024 * 1024;
3912
                    break;
3913
                }
3914
                feed->feed_max_size = (int64_t)fsize;
3915
            }
3916
        } else if (!strcasecmp(cmd, "</Feed>")) {
3917
            if (!feed) {
3918
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3919
                        filename, line_num);
3920
                errors++;
3921
            }
3922
            feed = NULL;
3923
        } else if (!strcasecmp(cmd, "<Stream")) {
3924
            /*********************************************/
3925
            /* Stream related options */
3926
            char *q;
3927
            if (stream || feed) {
3928
                fprintf(stderr, "%s:%d: Already in a tag\n",
3929
                        filename, line_num);
3930
            } else {
3931
                stream = av_mallocz(sizeof(FFStream));
3932
                *last_stream = stream;
3933
                last_stream = &stream->next;
3934

    
3935
                get_arg(stream->filename, sizeof(stream->filename), &p);
3936
                q = strrchr(stream->filename, '>');
3937
                if (*q)
3938
                    *q = '\0';
3939
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3940
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3941
                memset(&video_enc, 0, sizeof(AVCodecContext));
3942
                audio_id = CODEC_ID_NONE;
3943
                video_id = CODEC_ID_NONE;
3944
                if (stream->fmt) {
3945
                    audio_id = stream->fmt->audio_codec;
3946
                    video_id = stream->fmt->video_codec;
3947
                }
3948
            }
3949
        } else if (!strcasecmp(cmd, "Feed")) {
3950
            get_arg(arg, sizeof(arg), &p);
3951
            if (stream) {
3952
                FFStream *sfeed;
3953

    
3954
                sfeed = first_feed;
3955
                while (sfeed != NULL) {
3956
                    if (!strcmp(sfeed->filename, arg))
3957
                        break;
3958
                    sfeed = sfeed->next_feed;
3959
                }
3960
                if (!sfeed)
3961
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3962
                            filename, line_num, arg);
3963
                else
3964
                    stream->feed = sfeed;
3965
            }
3966
        } else if (!strcasecmp(cmd, "Format")) {
3967
            get_arg(arg, sizeof(arg), &p);
3968
            if (!strcmp(arg, "status")) {
3969
                stream->stream_type = STREAM_TYPE_STATUS;
3970
                stream->fmt = NULL;
3971
            } else {
3972
                stream->stream_type = STREAM_TYPE_LIVE;
3973
                /* jpeg cannot be used here, so use single frame jpeg */
3974
                if (!strcmp(arg, "jpeg"))
3975
                    strcpy(arg, "mjpeg");
3976
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3977
                if (!stream->fmt) {
3978
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
3979
                            filename, line_num, arg);
3980
                    errors++;
3981
                }
3982
            }
3983
            if (stream->fmt) {
3984
                audio_id = stream->fmt->audio_codec;
3985
                video_id = stream->fmt->video_codec;
3986
            }
3987
        } else if (!strcasecmp(cmd, "InputFormat")) {
3988
            get_arg(arg, sizeof(arg), &p);
3989
            stream->ifmt = av_find_input_format(arg);
3990
            if (!stream->ifmt) {
3991
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
3992
                        filename, line_num, arg);
3993
            }
3994
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3995
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3996
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3997
            } else {
3998
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
3999
                            filename, line_num);
4000
                errors++;
4001
            }
4002
        } else if (!strcasecmp(cmd, "Author")) {
4003
            if (stream)
4004
                get_arg(stream->author, sizeof(stream->author), &p);
4005
        } else if (!strcasecmp(cmd, "Comment")) {
4006
            if (stream)
4007
                get_arg(stream->comment, sizeof(stream->comment), &p);
4008
        } else if (!strcasecmp(cmd, "Copyright")) {
4009
            if (stream)
4010
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4011
        } else if (!strcasecmp(cmd, "Title")) {
4012
            if (stream)
4013
                get_arg(stream->title, sizeof(stream->title), &p);
4014
        } else if (!strcasecmp(cmd, "Preroll")) {
4015
            get_arg(arg, sizeof(arg), &p);
4016
            if (stream)
4017
                stream->prebuffer = atof(arg) * 1000;
4018
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4019
            if (stream)
4020
                stream->send_on_key = 1;
4021
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4022
            get_arg(arg, sizeof(arg), &p);
4023
            audio_id = opt_audio_codec(arg);
4024
            if (audio_id == CODEC_ID_NONE) {
4025
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4026
                        filename, line_num, arg);
4027
                errors++;
4028
            }
4029
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4030
            get_arg(arg, sizeof(arg), &p);
4031
            video_id = opt_video_codec(arg);
4032
            if (video_id == CODEC_ID_NONE) {
4033
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4034
                        filename, line_num, arg);
4035
                errors++;
4036
            }
4037
        } else if (!strcasecmp(cmd, "MaxTime")) {
4038
            get_arg(arg, sizeof(arg), &p);
4039
            if (stream)
4040
                stream->max_time = atof(arg) * 1000;
4041
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4042
            get_arg(arg, sizeof(arg), &p);
4043
            if (stream)
4044
                audio_enc.bit_rate = atoi(arg) * 1000;
4045
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4046
            get_arg(arg, sizeof(arg), &p);
4047
            if (stream)
4048
                audio_enc.channels = atoi(arg);
4049
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4050
            get_arg(arg, sizeof(arg), &p);
4051
            if (stream)
4052
                audio_enc.sample_rate = atoi(arg);
4053
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4054
            get_arg(arg, sizeof(arg), &p);
4055
            if (stream) {
4056
//                audio_enc.quality = atof(arg) * 1000;
4057
            }
4058
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4059
            if (stream) {
4060
                int minrate, maxrate;
4061

    
4062
                get_arg(arg, sizeof(arg), &p);
4063

    
4064
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4065
                    video_enc.rc_min_rate = minrate * 1000;
4066
                    video_enc.rc_max_rate = maxrate * 1000;
4067
                } else {
4068
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4069
                            filename, line_num, arg);
4070
                    errors++;
4071
                }
4072
            }
4073
        } else if (!strcasecmp(cmd, "Debug")) {
4074
            if (stream) {
4075
                get_arg(arg, sizeof(arg), &p);
4076
                video_enc.debug = strtol(arg,0,0);
4077
            }
4078
        } else if (!strcasecmp(cmd, "Strict")) {
4079
            if (stream) {
4080
                get_arg(arg, sizeof(arg), &p);
4081
                video_enc.strict_std_compliance = atoi(arg);
4082
            }
4083
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4084
            if (stream) {
4085
                get_arg(arg, sizeof(arg), &p);
4086
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4087
            }
4088
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4089
            if (stream) {
4090
                get_arg(arg, sizeof(arg), &p);
4091
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4092
            }
4093
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4094
            get_arg(arg, sizeof(arg), &p);
4095
            if (stream) {
4096
                video_enc.bit_rate = atoi(arg) * 1000;
4097
            }
4098
        } else if (!strcasecmp(cmd, "VideoSize")) {
4099
            get_arg(arg, sizeof(arg), &p);
4100
            if (stream) {
4101
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4102
                if ((video_enc.width % 16) != 0 ||
4103
                    (video_enc.height % 16) != 0) {
4104
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4105
                            filename, line_num);
4106
                    errors++;
4107
                }
4108
            }
4109
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4110
            get_arg(arg, sizeof(arg), &p);
4111
            if (stream) {
4112
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4113
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4114
            }
4115
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4116
            get_arg(arg, sizeof(arg), &p);
4117
            if (stream)
4118
                video_enc.gop_size = atoi(arg);
4119
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4120
            if (stream)
4121
                video_enc.gop_size = 1;
4122
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4123
            if (stream)
4124
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4125
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4126
            if (stream) {
4127
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4128
                video_enc.flags |= CODEC_FLAG_4MV;
4129
            }
4130
        } else if (!strcasecmp(cmd, "VideoTag")) {
4131
            get_arg(arg, sizeof(arg), &p);
4132
            if ((strlen(arg) == 4) && stream)
4133
                video_enc.codec_tag = ff_get_fourcc(arg);
4134
        } else if (!strcasecmp(cmd, "BitExact")) {
4135
            if (stream)
4136
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4137
        } else if (!strcasecmp(cmd, "DctFastint")) {
4138
            if (stream)
4139
                video_enc.dct_algo  = FF_DCT_FASTINT;
4140
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4141
            if (stream)
4142
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4143
        } else if (!strcasecmp(cmd, "Qscale")) {
4144
            get_arg(arg, sizeof(arg), &p);
4145
            if (stream) {
4146
                video_enc.flags |= CODEC_FLAG_QSCALE;
4147
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4148
            }
4149
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4150
            get_arg(arg, sizeof(arg), &p);
4151
            if (stream) {
4152
                video_enc.max_qdiff = atoi(arg);
4153
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4154
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4155
                            filename, line_num);
4156
                    errors++;
4157
                }
4158
            }
4159
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4160
            get_arg(arg, sizeof(arg), &p);
4161
            if (stream) {
4162
                video_enc.qmax = atoi(arg);
4163
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4164
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4165
                            filename, line_num);
4166
                    errors++;
4167
                }
4168
            }
4169
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4170
            get_arg(arg, sizeof(arg), &p);
4171
            if (stream) {
4172
                video_enc.qmin = atoi(arg);
4173
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4174
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4175
                            filename, line_num);
4176
                    errors++;
4177
                }
4178
            }
4179
        } else if (!strcasecmp(cmd, "LumaElim")) {
4180
            get_arg(arg, sizeof(arg), &p);
4181
            if (stream)
4182
                video_enc.luma_elim_threshold = atoi(arg);
4183
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4184
            get_arg(arg, sizeof(arg), &p);
4185
            if (stream)
4186
                video_enc.chroma_elim_threshold = atoi(arg);
4187
        } else if (!strcasecmp(cmd, "LumiMask")) {
4188
            get_arg(arg, sizeof(arg), &p);
4189
            if (stream)
4190
                video_enc.lumi_masking = atof(arg);
4191
        } else if (!strcasecmp(cmd, "DarkMask")) {
4192
            get_arg(arg, sizeof(arg), &p);
4193
            if (stream)
4194
                video_enc.dark_masking = atof(arg);
4195
        } else if (!strcasecmp(cmd, "NoVideo")) {
4196
            video_id = CODEC_ID_NONE;
4197
        } else if (!strcasecmp(cmd, "NoAudio")) {
4198
            audio_id = CODEC_ID_NONE;
4199
        } else if (!strcasecmp(cmd, "ACL")) {
4200
            IPAddressACL acl;
4201

    
4202
            get_arg(arg, sizeof(arg), &p);
4203
            if (strcasecmp(arg, "allow") == 0)
4204
                acl.action = IP_ALLOW;
4205
            else if (strcasecmp(arg, "deny") == 0)
4206
                acl.action = IP_DENY;
4207
            else {
4208
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4209
                        filename, line_num, arg);
4210
                errors++;
4211
            }
4212

    
4213
            get_arg(arg, sizeof(arg), &p);
4214

    
4215
            if (resolve_host(&acl.first, arg) != 0) {
4216
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4217
                        filename, line_num, arg);
4218
                errors++;
4219
            } else
4220
                acl.last = acl.first;
4221

    
4222
            get_arg(arg, sizeof(arg), &p);
4223

    
4224
            if (arg[0]) {
4225
                if (resolve_host(&acl.last, arg) != 0) {
4226
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4227
                            filename, line_num, arg);
4228
                    errors++;
4229
                }
4230
            }
4231

    
4232
            if (!errors) {
4233
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4234
                IPAddressACL **naclp = 0;
4235

    
4236
                acl.next = 0;
4237
                *nacl = acl;
4238

    
4239
                if (stream)
4240
                    naclp = &stream->acl;
4241
                else if (feed)
4242
                    naclp = &feed->acl;
4243
                else {
4244
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4245
                            filename, line_num);
4246
                    errors++;
4247
                }
4248

    
4249
                if (naclp) {
4250
                    while (*naclp)
4251
                        naclp = &(*naclp)->next;
4252

    
4253
                    *naclp = nacl;
4254
                }
4255
            }
4256
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4257
            get_arg(arg, sizeof(arg), &p);
4258
            if (stream) {
4259
                av_freep(&stream->rtsp_option);
4260
                stream->rtsp_option = av_strdup(arg);
4261
            }
4262
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4263
            get_arg(arg, sizeof(arg), &p);
4264
            if (stream) {
4265
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4266
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4267
                            filename, line_num, arg);
4268
                    errors++;
4269
                }
4270
                stream->is_multicast = 1;
4271
                stream->loop = 1; /* default is looping */
4272
            }
4273
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4274
            get_arg(arg, sizeof(arg), &p);
4275
            if (stream)
4276
                stream->multicast_port = atoi(arg);
4277
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4278
            get_arg(arg, sizeof(arg), &p);
4279
            if (stream)
4280
                stream->multicast_ttl = atoi(arg);
4281
        } else if (!strcasecmp(cmd, "NoLoop")) {
4282
            if (stream)
4283
                stream->loop = 0;
4284
        } else if (!strcasecmp(cmd, "</Stream>")) {
4285
            if (!stream) {
4286
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4287
                        filename, line_num);
4288
                errors++;
4289
            }
4290
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4291
                if (audio_id != CODEC_ID_NONE) {
4292
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4293
                    audio_enc.codec_id = audio_id;
4294
                    add_codec(stream, &audio_enc);
4295
                }
4296
                if (video_id != CODEC_ID_NONE) {
4297
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4298
                    video_enc.codec_id = video_id;
4299
                    add_codec(stream, &video_enc);
4300
                }
4301
            }
4302
            stream = NULL;
4303
        } else if (!strcasecmp(cmd, "<Redirect")) {
4304
            /*********************************************/
4305
            char *q;
4306
            if (stream || feed || redirect) {
4307
                fprintf(stderr, "%s:%d: Already in a tag\n",
4308
                        filename, line_num);
4309
                errors++;
4310
            } else {
4311
                redirect = av_mallocz(sizeof(FFStream));
4312
                *last_stream = redirect;
4313
                last_stream = &redirect->next;
4314

    
4315
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4316
                q = strrchr(redirect->filename, '>');
4317
                if (*q)
4318
                    *q = '\0';
4319
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4320
            }
4321
        } else if (!strcasecmp(cmd, "URL")) {
4322
            if (redirect)
4323
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4324
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4325
            if (!redirect) {
4326
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4327
                        filename, line_num);
4328
                errors++;
4329
            }
4330
            if (!redirect->feed_filename[0]) {
4331
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4332
                        filename, line_num);
4333
                errors++;
4334
            }
4335
            redirect = NULL;
4336
        } else if (!strcasecmp(cmd, "LoadModule")) {
4337
            get_arg(arg, sizeof(arg), &p);
4338
#ifdef HAVE_DLOPEN
4339
            load_module(arg);
4340
#else
4341
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4342
                    filename, line_num, arg);
4343
            errors++;
4344
#endif
4345
        } else {
4346
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4347
                    filename, line_num, cmd);
4348
            errors++;
4349
        }
4350
    }
4351

    
4352
    fclose(f);
4353
    if (errors)
4354
        return -1;
4355
    else
4356
        return 0;
4357
}
4358

    
4359
static void show_banner(void)
4360
{
4361
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4362
}
4363

    
4364
static void show_help(void)
4365
{
4366
    show_banner();
4367
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4368
           "Hyper fast multi format Audio/Video streaming server\n"
4369
           "\n"
4370
           "-L            : print the LICENSE\n"
4371
           "-h            : this help\n"
4372
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4373
           );
4374
}
4375

    
4376
static void show_license(void)
4377
{
4378
    show_banner();
4379
    printf(
4380
    "FFmpeg is free software; you can redistribute it and/or\n"
4381
    "modify it under the terms of the GNU Lesser General Public\n"
4382
    "License as published by the Free Software Foundation; either\n"
4383
    "version 2.1 of the License, or (at your option) any later version.\n"
4384
    "\n"
4385
    "FFmpeg is distributed in the hope that it will be useful,\n"
4386
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4387
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4388
    "Lesser General Public License for more details.\n"
4389
    "\n"
4390
    "You should have received a copy of the GNU Lesser General Public\n"
4391
    "License along with FFmpeg; if not, write to the Free Software\n"
4392
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
4393
    );
4394
}
4395

    
4396
static void handle_child_exit(int sig)
4397
{
4398
    pid_t pid;
4399
    int status;
4400

    
4401
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4402
        FFStream *feed;
4403

    
4404
        for (feed = first_feed; feed; feed = feed->next) {
4405
            if (feed->pid == pid) {
4406
                int uptime = time(0) - feed->pid_start;
4407

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

    
4411
                if (uptime < 30)
4412
                    /* Turn off any more restarts */
4413
                    feed->child_argv = 0;
4414
            }
4415
        }
4416
    }
4417

    
4418
    need_to_start_children = 1;
4419
}
4420

    
4421
int main(int argc, char **argv)
4422
{
4423
    const char *config_filename;
4424
    int c;
4425
    struct sigaction sigact;
4426

    
4427
    av_register_all();
4428

    
4429
    config_filename = "/etc/ffserver.conf";
4430

    
4431
    my_program_name = argv[0];
4432
    my_program_dir = getcwd(0, 0);
4433
    ffserver_daemon = 1;
4434

    
4435
    for(;;) {
4436
        c = getopt(argc, argv, "ndLh?f:");
4437
        if (c == -1)
4438
            break;
4439
        switch(c) {
4440
        case 'L':
4441
            show_license();
4442
            exit(0);
4443
        case '?':
4444
        case 'h':
4445
            show_help();
4446
            exit(0);
4447
        case 'n':
4448
            no_launch = 1;
4449
            break;
4450
        case 'd':
4451
            ffserver_debug = 1;
4452
            ffserver_daemon = 0;
4453
            break;
4454
        case 'f':
4455
            config_filename = optarg;
4456
            break;
4457
        default:
4458
            exit(2);
4459
        }
4460
    }
4461

    
4462
    putenv("http_proxy");               /* Kill the http_proxy */
4463

    
4464
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4465

    
4466
    /* address on which the server will handle HTTP connections */
4467
    my_http_addr.sin_family = AF_INET;
4468
    my_http_addr.sin_port = htons (8080);
4469
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4470

    
4471
    /* address on which the server will handle RTSP connections */
4472
    my_rtsp_addr.sin_family = AF_INET;
4473
    my_rtsp_addr.sin_port = htons (5454);
4474
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4475

    
4476
    nb_max_connections = 5;
4477
    max_bandwidth = 1000;
4478
    first_stream = NULL;
4479
    logfilename[0] = '\0';
4480

    
4481
    memset(&sigact, 0, sizeof(sigact));
4482
    sigact.sa_handler = handle_child_exit;
4483
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4484
    sigaction(SIGCHLD, &sigact, 0);
4485

    
4486
    if (parse_ffconfig(config_filename) < 0) {
4487
        fprintf(stderr, "Incorrect config file - exiting.\n");
4488
        exit(1);
4489
    }
4490

    
4491
    build_file_streams();
4492

    
4493
    build_feed_streams();
4494

    
4495
    compute_bandwidth();
4496

    
4497
    /* put the process in background and detach it from its TTY */
4498
    if (ffserver_daemon) {
4499
        int pid;
4500

    
4501
        pid = fork();
4502
        if (pid < 0) {
4503
            perror("fork");
4504
            exit(1);
4505
        } else if (pid > 0) {
4506
            /* parent : exit */
4507
            exit(0);
4508
        } else {
4509
            /* child */
4510
            setsid();
4511
            chdir("/");
4512
            close(0);
4513
            open("/dev/null", O_RDWR);
4514
            if (strcmp(logfilename, "-") != 0) {
4515
                close(1);
4516
                dup(0);
4517
            }
4518
            close(2);
4519
            dup(0);
4520
        }
4521
    }
4522

    
4523
    /* signal init */
4524
    signal(SIGPIPE, SIG_IGN);
4525

    
4526
    /* open log file if needed */
4527
    if (logfilename[0] != '\0') {
4528
        if (!strcmp(logfilename, "-"))
4529
            logfile = stdout;
4530
        else
4531
            logfile = fopen(logfilename, "w");
4532
    }
4533

    
4534
    if (http_server() < 0) {
4535
        fprintf(stderr, "Could not start server\n");
4536
        exit(1);
4537
    }
4538

    
4539
    return 0;
4540
}