Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 5509bffa

History | View | Annotate | Download (150 KB)

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

    
22
#include <stdarg.h>
23
#include <unistd.h>
24
#include <fcntl.h>
25
#include <sys/ioctl.h>
26
#include <sys/poll.h>
27
#include <errno.h>
28
#include <sys/time.h>
29
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
30
#include <time.h>
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/wait.h>
34
#include <netinet/in.h>
35
#include <arpa/inet.h>
36
#include <netdb.h>
37
#include <signal.h>
38
#ifdef CONFIG_HAVE_DLFCN
39
#include <dlfcn.h>
40
#endif
41

    
42
#include "ffserver.h"
43

    
44
/* maximum number of simultaneous HTTP connections */
45
#define HTTP_MAX_CONNECTIONS 2000
46

    
47
enum HTTPState {
48
    HTTPSTATE_WAIT_REQUEST,
49
    HTTPSTATE_SEND_HEADER,
50
    HTTPSTATE_SEND_DATA_HEADER,
51
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
52
    HTTPSTATE_SEND_DATA_TRAILER,
53
    HTTPSTATE_RECEIVE_DATA,
54
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
55
    HTTPSTATE_READY,
56

    
57
    RTSPSTATE_WAIT_REQUEST,
58
    RTSPSTATE_SEND_REPLY,
59
    RTSPSTATE_SEND_PACKET,
60
};
61

    
62
const char *http_state[] = {
63
    "HTTP_WAIT_REQUEST",
64
    "HTTP_SEND_HEADER",
65

    
66
    "SEND_DATA_HEADER",
67
    "SEND_DATA",
68
    "SEND_DATA_TRAILER",
69
    "RECEIVE_DATA",
70
    "WAIT_FEED",
71
    "READY",
72

    
73
    "RTSP_WAIT_REQUEST",
74
    "RTSP_SEND_REPLY",
75
    "RTSP_SEND_PACKET",
76
};
77

    
78
#define IOBUFFER_INIT_SIZE 8192
79

    
80
/* coef for exponential mean for bitrate estimation in statistics */
81
#define AVG_COEF 0.9
82

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

    
87
#define SYNC_TIMEOUT (10 * 1000)
88

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

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

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

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

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

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

    
157
static AVFrame dummy_frame;
158

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

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

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

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

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

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

    
232
struct sockaddr_in my_http_addr;
233
struct sockaddr_in my_rtsp_addr;
234

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

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

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

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

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

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

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

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

    
281
int nb_max_connections;
282
int nb_connections;
283

    
284
int max_bandwidth;
285
int current_bandwidth;
286

    
287
static long cur_time;           // Making this global saves on passing it around everywhere
288

    
289
static long gettime_ms(void)
290
{
291
    struct timeval tv;
292

    
293
    gettimeofday(&tv,NULL);
294
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
295
}
296

    
297
static FILE *logfile = NULL;
298

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

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

    
311
static char *ctime1(char *buf2)
312
{
313
    time_t ti;
314
    char *p;
315

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

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

    
329
    if (c->suppress_log)
330
        return;
331

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

    
338
static void update_datarate(DataRateData *drd, int64_t count)
339
{
340
    if (!drd->time1 && !drd->count1) {
341
        drd->time1 = drd->time2 = cur_time;
342
        drd->count1 = drd->count2 = count;
343
    } else {
344
        if (cur_time - drd->time2 > 5000) {
345
            drd->time1 = drd->time2;
346
            drd->count1 = drd->count2;
347
            drd->time2 = cur_time;
348
            drd->count2 = count;
349
        }
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
static int get_longterm_datarate(DataRateData *drd, int64_t count)
363
{
364
    /* You get the first 3 seconds flat out */
365
    if (cur_time - drd->time1 < 3000)
366
        return 0;
367
    return compute_datarate(drd, count);
368
}
369

    
370

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

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

    
380
            feed->pid = fork();
381

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

    
392
                for (i = 3; i < 256; i++) {
393
                    close(i);
394
                }
395

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

    
406
                pstrcpy(pathname, sizeof(pathname), my_program_name);
407

    
408
                slash = strrchr(pathname, '/');
409
                if (!slash) {
410
                    slash = pathname;
411
                } else {
412
                    slash++;
413
                }
414
                strcpy(slash, "ffmpeg");
415

    
416
                /* This is needed to make relative pathnames work */
417
                chdir(my_program_dir);
418

    
419
                signal(SIGPIPE, SIG_DFL);
420

    
421
                execvp(pathname, feed->child_argv);
422

    
423
                _exit(1);
424
            }
425
        }
426
    }
427
}
428

    
429
/* open a listening socket */
430
static int socket_open_listen(struct sockaddr_in *my_addr)
431
{
432
    int server_fd, tmp;
433

    
434
    server_fd = socket(AF_INET,SOCK_STREAM,0);
435
    if (server_fd < 0) {
436
        perror ("socket");
437
        return -1;
438
    }
439

    
440
    tmp = 1;
441
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
442

    
443
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
444
        char bindmsg[32];
445
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
446
        perror (bindmsg);
447
        close(server_fd);
448
        return -1;
449
    }
450

    
451
    if (listen (server_fd, 5) < 0) {
452
        perror ("listen");
453
        close(server_fd);
454
        return -1;
455
    }
456
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
457

    
458
    return server_fd;
459
}
460

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

    
470
    default_port = 6000;
471
    for(stream = first_stream; stream != NULL; stream = stream->next) {
472
        if (stream->is_multicast) {
473
            /* open the RTP connection */
474
            snprintf(session_id, sizeof(session_id),
475
                     "%08x%08x", (int)random(), (int)random());
476

    
477
            /* choose a port if none given */
478
            if (stream->multicast_port == 0) {
479
                stream->multicast_port = default_port;
480
                default_port += 100;
481
            }
482

    
483
            dest_addr.sin_family = AF_INET;
484
            dest_addr.sin_addr = stream->multicast_ip;
485
            dest_addr.sin_port = htons(stream->multicast_port);
486

    
487
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
488
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
489
            if (!rtp_c) {
490
                continue;
491
            }
492
            if (open_input_stream(rtp_c, "") < 0) {
493
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
494
                        stream->filename);
495
                continue;
496
            }
497

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

    
510
            /* change state to send data */
511
            rtp_c->state = HTTPSTATE_SEND_DATA;
512
        }
513
    }
514
}
515

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

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

    
527
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
528
    if (rtsp_server_fd < 0)
529
        return -1;
530

    
531
    http_log("ffserver started.\n");
532

    
533
    start_children(first_feed);
534

    
535
    first_http_ctx = NULL;
536
    nb_connections = 0;
537

    
538
    start_multicast();
539

    
540
    for(;;) {
541
        poll_entry = poll_table;
542
        poll_entry->fd = server_fd;
543
        poll_entry->events = POLLIN;
544
        poll_entry++;
545

    
546
        poll_entry->fd = rtsp_server_fd;
547
        poll_entry->events = POLLIN;
548
        poll_entry++;
549

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

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

    
608
        cur_time = gettime_ms();
609

    
610
        if (need_to_start_children) {
611
            need_to_start_children = 0;
612
            start_children(first_feed);
613
        }
614

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

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

    
638
/* start waiting for a new HTTP/RTSP request */
639
static void start_wait_request(HTTPContext *c, int is_rtsp)
640
{
641
    c->buffer_ptr = c->buffer;
642
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
643

    
644
    if (is_rtsp) {
645
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
646
        c->state = RTSPSTATE_WAIT_REQUEST;
647
    } else {
648
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
649
        c->state = HTTPSTATE_WAIT_REQUEST;
650
    }
651
}
652

    
653
static void new_connection(int server_fd, int is_rtsp)
654
{
655
    struct sockaddr_in from_addr;
656
    int fd, len;
657
    HTTPContext *c = NULL;
658

    
659
    len = sizeof(from_addr);
660
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
661
                &len);
662
    if (fd < 0)
663
        return;
664
    fcntl(fd, F_SETFL, O_NONBLOCK);
665

    
666
    /* XXX: should output a warning page when coming
667
       close to the connection limit */
668
    if (nb_connections >= nb_max_connections)
669
        goto fail;
670

    
671
    /* add a new connection */
672
    c = av_mallocz(sizeof(HTTPContext));
673
    if (!c)
674
        goto fail;
675

    
676
    c->fd = fd;
677
    c->poll_entry = NULL;
678
    c->from_addr = from_addr;
679
    c->buffer_size = IOBUFFER_INIT_SIZE;
680
    c->buffer = av_malloc(c->buffer_size);
681
    if (!c->buffer)
682
        goto fail;
683

    
684
    c->next = first_http_ctx;
685
    first_http_ctx = c;
686
    nb_connections++;
687

    
688
    start_wait_request(c, is_rtsp);
689

    
690
    return;
691

    
692
 fail:
693
    if (c) {
694
        av_free(c->buffer);
695
        av_free(c);
696
    }
697
    close(fd);
698
}
699

    
700
static void close_connection(HTTPContext *c)
701
{
702
    HTTPContext **cp, *c1;
703
    int i, nb_streams;
704
    AVFormatContext *ctx;
705
    URLContext *h;
706
    AVStream *st;
707

    
708
    /* remove connection from list */
709
    cp = &first_http_ctx;
710
    while ((*cp) != NULL) {
711
        c1 = *cp;
712
        if (c1 == c) {
713
            *cp = c->next;
714
        } else {
715
            cp = &c1->next;
716
        }
717
    }
718

    
719
    /* remove references, if any (XXX: do it faster) */
720
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
721
        if (c1->rtsp_c == c)
722
            c1->rtsp_c = NULL;
723
    }
724

    
725
    /* remove connection associated resources */
726
    if (c->fd >= 0)
727
        close(c->fd);
728
    if (c->fmt_in) {
729
        /* close each frame parser */
730
        for(i=0;i<c->fmt_in->nb_streams;i++) {
731
            st = c->fmt_in->streams[i];
732
            if (st->codec->codec) {
733
                avcodec_close(st->codec);
734
            }
735
        }
736
        av_close_input_file(c->fmt_in);
737
    }
738

    
739
    /* free RTP output streams if any */
740
    nb_streams = 0;
741
    if (c->stream)
742
        nb_streams = c->stream->nb_streams;
743

    
744
    for(i=0;i<nb_streams;i++) {
745
        ctx = c->rtp_ctx[i];
746
        if (ctx) {
747
            av_write_trailer(ctx);
748
            av_free(ctx);
749
        }
750
        h = c->rtp_handles[i];
751
        if (h) {
752
            url_close(h);
753
        }
754
    }
755

    
756
    ctx = &c->fmt_ctx;
757

    
758
    if (!c->last_packet_sent) {
759
        if (ctx->oformat) {
760
            /* prepare header */
761
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
762
                av_write_trailer(ctx);
763
                url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
764
            }
765
        }
766
    }
767

    
768
    for(i=0; i<ctx->nb_streams; i++)
769
        av_free(ctx->streams[i]) ;
770

    
771
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
772
        current_bandwidth -= c->stream->bandwidth;
773
    av_freep(&c->pb_buffer);
774
    av_freep(&c->packet_buffer);
775
    av_free(c->buffer);
776
    av_free(c);
777
    nb_connections--;
778
}
779

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

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

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

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

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

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

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

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

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

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

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

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

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

    
966
                q += 20;
967

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

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

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

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

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

    
993
        p++;
994
    }
995

    
996
    return 0;
997
}
998

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

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

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

    
1015
        /* Potential stream */
1016

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

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

    
1034
    return best;
1035
}
1036

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

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

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

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

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

    
1072
    return action_required;
1073
}
1074

    
1075

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1233
        p++;
1234
    }
1235

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

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

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

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

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

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

    
1298
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1299
        current_bandwidth += stream->bandwidth;
1300
    }
1301

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

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

    
1321
    if (redir_type != REDIR_NONE) {
1322
        char *hostinfo = 0;
1323

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

    
1333
            p++;
1334
        }
1335

    
1336
        if (hostinfo) {
1337
            char *eoh;
1338
            char hostbuf[260];
1339

    
1340
            while (isspace(*hostinfo))
1341
                hostinfo++;
1342

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

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

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

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

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

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

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

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

    
1441
    stream->conns_served++;
1442

    
1443
    /* XXX: add there authenticate and IP match */
1444

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

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

    
1466
                p++;
1467
            }
1468

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

    
1472
                logline += 17;
1473

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

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

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

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

    
1495
                if (wmpc) {
1496
                    if (modify_current_stream(wmpc, ratebuf)) {
1497
                        wmpc->switch_pending = 1;
1498
                    }
1499
                }
1500
            }
1501

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

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

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

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

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

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

    
1542
        c->wmp_client_id = random() & 0x7fffffff;
1543

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1754
                parameters[0] = 0;
1755

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1932
    /* open each parser */
1933
    for(i=0;i<s->nb_streams;i++)
1934
        open_parser(s, i);
1935

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

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

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

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

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

    
1980

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

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

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

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

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

    
2033
        av_set_parameters(&c->fmt_ctx, NULL);
2034
        av_write_header(&c->fmt_ctx);
2035

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

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

    
2048
            /* read a packet from the input stream */
2049
            if (c->stream->feed) {
2050
                ffm_set_write_index(c->fmt_in,
2051
                                    c->stream->feed->feed_write_index,
2052
                                    c->stream->feed->feed_size);
2053
            }
2054

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

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

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

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

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

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

    
2215
/* in bit/s */
2216
#define SHORT_TERM_BANDWIDTH 8000000
2217

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

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

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

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

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

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

    
2344
static int http_start_receive_data(HTTPContext *c)
2345
{
2346
    int fd;
2347

    
2348
    if (c->stream->feed_opened)
2349
        return -1;
2350

    
2351
    /* Don't permit writing to this one */
2352
    if (c->stream->readonly)
2353
        return -1;
2354

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

    
2361
    c->stream->feed_write_index = ffm_read_write_index(fd);
2362
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2363
    lseek(fd, 0, SEEK_SET);
2364

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

    
2372
static int http_receive_data(HTTPContext *c)
2373
{
2374
    HTTPContext *c1;
2375

    
2376
    if (c->buffer_end > c->buffer_ptr) {
2377
        int len;
2378

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

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

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

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

    
2414
            feed->feed_write_index += FFM_PACKET_SIZE;
2415
            /* update file size */
2416
            if (feed->feed_write_index > c->stream->feed_size)
2417
                feed->feed_size = feed->feed_write_index;
2418

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

    
2423
            /* write index */
2424
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2425

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

    
2440
            memset(&s, 0, sizeof(s));
2441

    
2442
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2443
            pb->buf_end = c->buffer_end;        /* ?? */
2444
            pb->is_streamed = 1;
2445

    
2446
            /* use feed output format name to find corresponding input format */
2447
            fmt_in = av_find_input_format(feed->fmt->name);
2448
            if (!fmt_in)
2449
                goto fail;
2450

    
2451
            if (fmt_in->priv_data_size > 0) {
2452
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2453
                if (!s.priv_data)
2454
                    goto fail;
2455
            } else
2456
                s.priv_data = NULL;
2457

    
2458
            if (fmt_in->read_header(&s, 0) < 0) {
2459
                av_freep(&s.priv_data);
2460
                goto fail;
2461
            }
2462

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

    
2477
    return 0;
2478
 fail:
2479
    c->stream->feed_opened = 0;
2480
    close(c->feed_fd);
2481
    return -1;
2482
}
2483

    
2484
/********************************************************************/
2485
/* RTSP handling */
2486

    
2487
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2488
{
2489
    const char *str;
2490
    time_t ti;
2491
    char *p;
2492
    char buf2[32];
2493

    
2494
    switch(error_number) {
2495
#define DEF(n, c, s) case c: str = s; break;
2496
#include "rtspcodes.h"
2497
#undef DEF
2498
    default:
2499
        str = "Unknown Error";
2500
        break;
2501
    }
2502

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

    
2506
    /* output GMT time */
2507
    ti = time(NULL);
2508
    p = ctime(&ti);
2509
    strcpy(buf2, p);
2510
    p = buf2 + strlen(p) - 1;
2511
    if (*p == '\n')
2512
        *p = '\0';
2513
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2514
}
2515

    
2516
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2517
{
2518
    rtsp_reply_header(c, error_number);
2519
    url_fprintf(c->pb, "\r\n");
2520
}
2521

    
2522
static int rtsp_parse_request(HTTPContext *c)
2523
{
2524
    const char *p, *p1, *p2;
2525
    char cmd[32];
2526
    char url[1024];
2527
    char protocol[32];
2528
    char line[1024];
2529
    ByteIOContext pb1;
2530
    int len;
2531
    RTSPHeader header1, *header = &header1;
2532

    
2533
    c->buffer_ptr[0] = '\0';
2534
    p = c->buffer;
2535

    
2536
    get_word(cmd, sizeof(cmd), &p);
2537
    get_word(url, sizeof(url), &p);
2538
    get_word(protocol, sizeof(protocol), &p);
2539

    
2540
    pstrcpy(c->method, sizeof(c->method), cmd);
2541
    pstrcpy(c->url, sizeof(c->url), url);
2542
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2543

    
2544
    c->pb = &pb1;
2545
    if (url_open_dyn_buf(c->pb) < 0) {
2546
        /* XXX: cannot do more */
2547
        c->pb = NULL; /* safety */
2548
        return -1;
2549
    }
2550

    
2551
    /* check version name */
2552
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2553
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2554
        goto the_end;
2555
    }
2556

    
2557
    /* parse each header line */
2558
    memset(header, 0, sizeof(RTSPHeader));
2559
    /* skip to next line */
2560
    while (*p != '\n' && *p != '\0')
2561
        p++;
2562
    if (*p == '\n')
2563
        p++;
2564
    while (*p != '\0') {
2565
        p1 = strchr(p, '\n');
2566
        if (!p1)
2567
            break;
2568
        p2 = p1;
2569
        if (p2 > p && p2[-1] == '\r')
2570
            p2--;
2571
        /* skip empty line */
2572
        if (p2 == p)
2573
            break;
2574
        len = p2 - p;
2575
        if (len > sizeof(line) - 1)
2576
            len = sizeof(line) - 1;
2577
        memcpy(line, p, len);
2578
        line[len] = '\0';
2579
        rtsp_parse_line(header, line);
2580
        p = p1 + 1;
2581
    }
2582

    
2583
    /* handle sequence number */
2584
    c->seq = header->seq;
2585

    
2586
    if (!strcmp(cmd, "DESCRIBE")) {
2587
        rtsp_cmd_describe(c, url);
2588
    } else if (!strcmp(cmd, "OPTIONS")) {
2589
        rtsp_cmd_options(c, url);
2590
    } else if (!strcmp(cmd, "SETUP")) {
2591
        rtsp_cmd_setup(c, url, header);
2592
    } else if (!strcmp(cmd, "PLAY")) {
2593
        rtsp_cmd_play(c, url, header);
2594
    } else if (!strcmp(cmd, "PAUSE")) {
2595
        rtsp_cmd_pause(c, url, header);
2596
    } else if (!strcmp(cmd, "TEARDOWN")) {
2597
        rtsp_cmd_teardown(c, url, header);
2598
    } else {
2599
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2600
    }
2601
 the_end:
2602
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2603
    c->pb = NULL; /* safety */
2604
    if (len < 0) {
2605
        /* XXX: cannot do more */
2606
        return -1;
2607
    }
2608
    c->buffer_ptr = c->pb_buffer;
2609
    c->buffer_end = c->pb_buffer + len;
2610
    c->state = RTSPSTATE_SEND_REPLY;
2611
    return 0;
2612
}
2613

    
2614
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2615
   AVFormatContext */
2616
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2617
                                   struct in_addr my_ip)
2618
{
2619
    ByteIOContext pb1, *pb = &pb1;
2620
    int i, payload_type, port, private_payload_type, j;
2621
    const char *ipstr, *title, *mediatype;
2622
    AVStream *st;
2623

    
2624
    if (url_open_dyn_buf(pb) < 0)
2625
        return -1;
2626

    
2627
    /* general media info */
2628

    
2629
    url_fprintf(pb, "v=0\n");
2630
    ipstr = inet_ntoa(my_ip);
2631
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2632
    title = stream->title;
2633
    if (title[0] == '\0')
2634
        title = "No Title";
2635
    url_fprintf(pb, "s=%s\n", title);
2636
    if (stream->comment[0] != '\0')
2637
        url_fprintf(pb, "i=%s\n", stream->comment);
2638
    if (stream->is_multicast) {
2639
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2640
    }
2641
    /* for each stream, we output the necessary info */
2642
    private_payload_type = RTP_PT_PRIVATE;
2643
    for(i = 0; i < stream->nb_streams; i++) {
2644
        st = stream->streams[i];
2645
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2646
            mediatype = "video";
2647
        } else {
2648
            switch(st->codec->codec_type) {
2649
            case CODEC_TYPE_AUDIO:
2650
                mediatype = "audio";
2651
                break;
2652
            case CODEC_TYPE_VIDEO:
2653
                mediatype = "video";
2654
                break;
2655
            default:
2656
                mediatype = "application";
2657
                break;
2658
            }
2659
        }
2660
        /* NOTE: the port indication is not correct in case of
2661
           unicast. It is not an issue because RTSP gives it */
2662
        payload_type = rtp_get_payload_type(st->codec);
2663
        if (payload_type < 0)
2664
            payload_type = private_payload_type++;
2665
        if (stream->is_multicast) {
2666
            port = stream->multicast_port + 2 * i;
2667
        } else {
2668
            port = 0;
2669
        }
2670
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2671
                    mediatype, port, payload_type);
2672
        if (payload_type >= RTP_PT_PRIVATE) {
2673
            /* for private payload type, we need to give more info */
2674
            switch(st->codec->codec_id) {
2675
            case CODEC_ID_MPEG4:
2676
                {
2677
                    uint8_t *data;
2678
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2679
                                payload_type, 90000);
2680
                    /* we must also add the mpeg4 header */
2681
                    data = st->codec->extradata;
2682
                    if (data) {
2683
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2684
                        for(j=0;j<st->codec->extradata_size;j++) {
2685
                            url_fprintf(pb, "%02x", data[j]);
2686
                        }
2687
                        url_fprintf(pb, "\n");
2688
                    }
2689
                }
2690
                break;
2691
            default:
2692
                /* XXX: add other codecs ? */
2693
                goto fail;
2694
            }
2695
        }
2696
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2697
    }
2698
    return url_close_dyn_buf(pb, pbuffer);
2699
 fail:
2700
    url_close_dyn_buf(pb, pbuffer);
2701
    av_free(*pbuffer);
2702
    return -1;
2703
}
2704

    
2705
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2706
{
2707
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2708
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2709
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2710
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2711
    url_fprintf(c->pb, "\r\n");
2712
}
2713

    
2714
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2715
{
2716
    FFStream *stream;
2717
    char path1[1024];
2718
    const char *path;
2719
    uint8_t *content;
2720
    int content_length, len;
2721
    struct sockaddr_in my_addr;
2722

    
2723
    /* find which url is asked */
2724
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2725
    path = path1;
2726
    if (*path == '/')
2727
        path++;
2728

    
2729
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2730
        if (!stream->is_feed && stream->fmt == &rtp_mux &&
2731
            !strcmp(path, stream->filename)) {
2732
            goto found;
2733
        }
2734
    }
2735
    /* no stream found */
2736
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2737
    return;
2738

    
2739
 found:
2740
    /* prepare the media description in sdp format */
2741

    
2742
    /* get the host IP */
2743
    len = sizeof(my_addr);
2744
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2745
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2746
    if (content_length < 0) {
2747
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2748
        return;
2749
    }
2750
    rtsp_reply_header(c, RTSP_STATUS_OK);
2751
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2752
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2753
    url_fprintf(c->pb, "\r\n");
2754
    put_buffer(c->pb, content, content_length);
2755
}
2756

    
2757
static HTTPContext *find_rtp_session(const char *session_id)
2758
{
2759
    HTTPContext *c;
2760

    
2761
    if (session_id[0] == '\0')
2762
        return NULL;
2763

    
2764
    for(c = first_http_ctx; c != NULL; c = c->next) {
2765
        if (!strcmp(c->session_id, session_id))
2766
            return c;
2767
    }
2768
    return NULL;
2769
}
2770

    
2771
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2772
{
2773
    RTSPTransportField *th;
2774
    int i;
2775

    
2776
    for(i=0;i<h->nb_transports;i++) {
2777
        th = &h->transports[i];
2778
        if (th->protocol == protocol)
2779
            return th;
2780
    }
2781
    return NULL;
2782
}
2783

    
2784
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2785
                           RTSPHeader *h)
2786
{
2787
    FFStream *stream;
2788
    int stream_index, port;
2789
    char buf[1024];
2790
    char path1[1024];
2791
    const char *path;
2792
    HTTPContext *rtp_c;
2793
    RTSPTransportField *th;
2794
    struct sockaddr_in dest_addr;
2795
    RTSPActionServerSetup setup;
2796

    
2797
    /* find which url is asked */
2798
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2799
    path = path1;
2800
    if (*path == '/')
2801
        path++;
2802

    
2803
    /* now check each stream */
2804
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2805
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2806
            /* accept aggregate filenames only if single stream */
2807
            if (!strcmp(path, stream->filename)) {
2808
                if (stream->nb_streams != 1) {
2809
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2810
                    return;
2811
                }
2812
                stream_index = 0;
2813
                goto found;
2814
            }
2815

    
2816
            for(stream_index = 0; stream_index < stream->nb_streams;
2817
                stream_index++) {
2818
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2819
                         stream->filename, stream_index);
2820
                if (!strcmp(path, buf))
2821
                    goto found;
2822
            }
2823
        }
2824
    }
2825
    /* no stream found */
2826
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2827
    return;
2828
 found:
2829

    
2830
    /* generate session id if needed */
2831
    if (h->session_id[0] == '\0') {
2832
        snprintf(h->session_id, sizeof(h->session_id),
2833
                 "%08x%08x", (int)random(), (int)random());
2834
    }
2835

    
2836
    /* find rtp session, and create it if none found */
2837
    rtp_c = find_rtp_session(h->session_id);
2838
    if (!rtp_c) {
2839
        /* always prefer UDP */
2840
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2841
        if (!th) {
2842
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2843
            if (!th) {
2844
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2845
                return;
2846
            }
2847
        }
2848

    
2849
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2850
                                   th->protocol);
2851
        if (!rtp_c) {
2852
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2853
            return;
2854
        }
2855

    
2856
        /* open input stream */
2857
        if (open_input_stream(rtp_c, "") < 0) {
2858
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2859
            return;
2860
        }
2861
    }
2862

    
2863
    /* test if stream is OK (test needed because several SETUP needs
2864
       to be done for a given file) */
2865
    if (rtp_c->stream != stream) {
2866
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2867
        return;
2868
    }
2869

    
2870
    /* test if stream is already set up */
2871
    if (rtp_c->rtp_ctx[stream_index]) {
2872
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2873
        return;
2874
    }
2875

    
2876
    /* check transport */
2877
    th = find_transport(h, rtp_c->rtp_protocol);
2878
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2879
                th->client_port_min <= 0)) {
2880
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2881
        return;
2882
    }
2883

    
2884
    /* setup default options */
2885
    setup.transport_option[0] = '\0';
2886
    dest_addr = rtp_c->from_addr;
2887
    dest_addr.sin_port = htons(th->client_port_min);
2888

    
2889
    /* add transport option if needed */
2890
    if (ff_rtsp_callback) {
2891
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2892
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2893
                             (char *)&setup, sizeof(setup),
2894
                             stream->rtsp_option) < 0) {
2895
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2896
            return;
2897
        }
2898
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2899
    }
2900

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

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

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

    
2932

    
2933
    url_fprintf(c->pb, "\r\n");
2934
}
2935

    
2936

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

    
2948
    rtp_c = find_rtp_session(session_id);
2949
    if (!rtp_c)
2950
        return NULL;
2951

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

    
2969
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2970
{
2971
    HTTPContext *rtp_c;
2972

    
2973
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2974
    if (!rtp_c) {
2975
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2976
        return;
2977
    }
2978

    
2979
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2980
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2981
        rtp_c->state != HTTPSTATE_READY) {
2982
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2983
        return;
2984
    }
2985

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

    
2994
    rtp_c->state = HTTPSTATE_SEND_DATA;
2995

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

    
3003
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3004
{
3005
    HTTPContext *rtp_c;
3006

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

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

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

    
3028
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3029
{
3030
    HTTPContext *rtp_c;
3031

    
3032
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3033
    if (!rtp_c) {
3034
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3035
        return;
3036
    }
3037

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

    
3041
    if (ff_rtsp_callback) {
3042
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3043
                         NULL, 0,
3044
                         rtp_c->stream->rtsp_option);
3045
    }
3046

    
3047
    /* now everything is OK, so we can send the connection parameters */
3048
    rtsp_reply_header(c, RTSP_STATUS_OK);
3049
    /* session ID */
3050
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3051
    url_fprintf(c->pb, "\r\n");
3052
}
3053

    
3054

    
3055
/********************************************************************/
3056
/* RTP handling */
3057

    
3058
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3059
                                       FFStream *stream, const char *session_id,
3060
                                       enum RTSPProtocol rtp_protocol)
3061
{
3062
    HTTPContext *c = NULL;
3063
    const char *proto_str;
3064

    
3065
    /* XXX: should output a warning page when coming
3066
       close to the connection limit */
3067
    if (nb_connections >= nb_max_connections)
3068
        goto fail;
3069

    
3070
    /* add a new connection */
3071
    c = av_mallocz(sizeof(HTTPContext));
3072
    if (!c)
3073
        goto fail;
3074

    
3075
    c->fd = -1;
3076
    c->poll_entry = NULL;
3077
    c->from_addr = *from_addr;
3078
    c->buffer_size = IOBUFFER_INIT_SIZE;
3079
    c->buffer = av_malloc(c->buffer_size);
3080
    if (!c->buffer)
3081
        goto fail;
3082
    nb_connections++;
3083
    c->stream = stream;
3084
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3085
    c->state = HTTPSTATE_READY;
3086
    c->is_packetized = 1;
3087
    c->rtp_protocol = rtp_protocol;
3088

    
3089
    /* protocol is shown in statistics */
3090
    switch(c->rtp_protocol) {
3091
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3092
        proto_str = "MCAST";
3093
        break;
3094
    case RTSP_PROTOCOL_RTP_UDP:
3095
        proto_str = "UDP";
3096
        break;
3097
    case RTSP_PROTOCOL_RTP_TCP:
3098
        proto_str = "TCP";
3099
        break;
3100
    default:
3101
        proto_str = "???";
3102
        break;
3103
    }
3104
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3105
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3106

    
3107
    current_bandwidth += stream->bandwidth;
3108

    
3109
    c->next = first_http_ctx;
3110
    first_http_ctx = c;
3111
    return c;
3112

    
3113
 fail:
3114
    if (c) {
3115
        av_free(c->buffer);
3116
        av_free(c);
3117
    }
3118
    return NULL;
3119
}
3120

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

    
3136
    /* now we can open the relevant output stream */
3137
    ctx = av_alloc_format_context();
3138
    if (!ctx)
3139
        return -1;
3140
    ctx->oformat = &rtp_mux;
3141

    
3142
    st = av_mallocz(sizeof(AVStream));
3143
    if (!st)
3144
        goto fail;
3145
    st->codec= avcodec_alloc_context();
3146
    ctx->nb_streams = 1;
3147
    ctx->streams[0] = st;
3148

    
3149
    if (!c->stream->feed ||
3150
        c->stream->feed == c->stream) {
3151
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3152
    } else {
3153
        memcpy(st,
3154
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3155
               sizeof(AVStream));
3156
    }
3157

    
3158
    /* build destination RTP address */
3159
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3160

    
3161
    switch(c->rtp_protocol) {
3162
    case RTSP_PROTOCOL_RTP_UDP:
3163
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3164
        /* RTP/UDP case */
3165

    
3166
        /* XXX: also pass as parameter to function ? */
3167
        if (c->stream->is_multicast) {
3168
            int ttl;
3169
            ttl = c->stream->multicast_ttl;
3170
            if (!ttl)
3171
                ttl = 16;
3172
            snprintf(ctx->filename, sizeof(ctx->filename),
3173
                     "rtp://%s:%d?multicast=1&ttl=%d",
3174
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3175
        } else {
3176
            snprintf(ctx->filename, sizeof(ctx->filename),
3177
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3178
        }
3179

    
3180
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3181
            goto fail;
3182
        c->rtp_handles[stream_index] = h;
3183
        max_packet_size = url_get_max_packet_size(h);
3184
        break;
3185
    case RTSP_PROTOCOL_RTP_TCP:
3186
        /* RTP/TCP case */
3187
        c->rtsp_c = rtsp_c;
3188
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3189
        break;
3190
    default:
3191
        goto fail;
3192
    }
3193

    
3194
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3195
             ipaddr, ntohs(dest_addr->sin_port),
3196
             ctime1(buf2),
3197
             c->stream->filename, stream_index, c->protocol);
3198

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

    
3215
    c->rtp_ctx[stream_index] = ctx;
3216
    return 0;
3217
}
3218

    
3219
/********************************************************************/
3220
/* ffserver initialization */
3221

    
3222
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3223
{
3224
    AVStream *fst;
3225

    
3226
    fst = av_mallocz(sizeof(AVStream));
3227
    if (!fst)
3228
        return NULL;
3229
    fst->codec= avcodec_alloc_context();
3230
    fst->priv_data = av_mallocz(sizeof(FeedData));
3231
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3232
    fst->codec->coded_frame = &dummy_frame;
3233
    fst->index = stream->nb_streams;
3234
    av_set_pts_info(fst, 33, 1, 90000);
3235
    stream->streams[stream->nb_streams++] = fst;
3236
    return fst;
3237
}
3238

    
3239
/* return the stream number in the feed */
3240
static int add_av_stream(FFStream *feed, AVStream *st)
3241
{
3242
    AVStream *fst;
3243
    AVCodecContext *av, *av1;
3244
    int i;
3245

    
3246
    av = st->codec;
3247
    for(i=0;i<feed->nb_streams;i++) {
3248
        st = feed->streams[i];
3249
        av1 = st->codec;
3250
        if (av1->codec_id == av->codec_id &&
3251
            av1->codec_type == av->codec_type &&
3252
            av1->bit_rate == av->bit_rate) {
3253

    
3254
            switch(av->codec_type) {
3255
            case CODEC_TYPE_AUDIO:
3256
                if (av1->channels == av->channels &&
3257
                    av1->sample_rate == av->sample_rate)
3258
                    goto found;
3259
                break;
3260
            case CODEC_TYPE_VIDEO:
3261
                if (av1->width == av->width &&
3262
                    av1->height == av->height &&
3263
                    av1->time_base.den == av->time_base.den &&
3264
                    av1->time_base.num == av->time_base.num &&
3265
                    av1->gop_size == av->gop_size)
3266
                    goto found;
3267
                break;
3268
            default:
3269
                av_abort();
3270
            }
3271
        }
3272
    }
3273

    
3274
    fst = add_av_stream1(feed, av);
3275
    if (!fst)
3276
        return -1;
3277
    return feed->nb_streams - 1;
3278
 found:
3279
    return i;
3280
}
3281

    
3282
static void remove_stream(FFStream *stream)
3283
{
3284
    FFStream **ps;
3285
    ps = &first_stream;
3286
    while (*ps != NULL) {
3287
        if (*ps == stream) {
3288
            *ps = (*ps)->next;
3289
        } else {
3290
            ps = &(*ps)->next;
3291
        }
3292
    }
3293
}
3294

    
3295
/* specific mpeg4 handling : we extract the raw parameters */
3296
static void extract_mpeg4_header(AVFormatContext *infile)
3297
{
3298
    int mpeg4_count, i, size;
3299
    AVPacket pkt;
3300
    AVStream *st;
3301
    const uint8_t *p;
3302

    
3303
    mpeg4_count = 0;
3304
    for(i=0;i<infile->nb_streams;i++) {
3305
        st = infile->streams[i];
3306
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3307
            st->codec->extradata_size == 0) {
3308
            mpeg4_count++;
3309
        }
3310
    }
3311
    if (!mpeg4_count)
3312
        return;
3313

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

    
3344
/* compute the needed AVStream for each file */
3345
static void build_file_streams(void)
3346
{
3347
    FFStream *stream, *stream_next;
3348
    AVFormatContext *infile;
3349
    int i;
3350

    
3351
    /* gather all streams */
3352
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3353
        stream_next = stream->next;
3354
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3355
            !stream->feed) {
3356
            /* the stream comes from a file */
3357
            /* try to open the file */
3358
            /* open stream */
3359
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3360
            if (stream->fmt == &rtp_mux) {
3361
                /* specific case : if transport stream output to RTP,
3362
                   we use a raw transport stream reader */
3363
                stream->ap_in->mpeg2ts_raw = 1;
3364
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3365
            }
3366

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

    
3384
                for(i=0;i<infile->nb_streams;i++) {
3385
                    add_av_stream1(stream, infile->streams[i]->codec);
3386
                }
3387
                av_close_input_file(infile);
3388
            }
3389
        }
3390
    }
3391
}
3392

    
3393
/* compute the needed AVStream for each feed */
3394
static void build_feed_streams(void)
3395
{
3396
    FFStream *stream, *feed;
3397
    int i;
3398

    
3399
    /* gather all streams */
3400
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3401
        feed = stream->feed;
3402
        if (feed) {
3403
            if (!stream->is_feed) {
3404
                /* we handle a stream coming from a feed */
3405
                for(i=0;i<stream->nb_streams;i++) {
3406
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3407
                }
3408
            }
3409
        }
3410
    }
3411

    
3412
    /* gather all streams */
3413
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3414
        feed = stream->feed;
3415
        if (feed) {
3416
            if (stream->is_feed) {
3417
                for(i=0;i<stream->nb_streams;i++) {
3418
                    stream->feed_streams[i] = i;
3419
                }
3420
            }
3421
        }
3422
    }
3423

    
3424
    /* create feed files if needed */
3425
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3426
        int fd;
3427

    
3428
        if (url_exist(feed->feed_filename)) {
3429
            /* See if it matches */
3430
            AVFormatContext *s;
3431
            int matches = 0;
3432

    
3433
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3434
                /* Now see if it matches */
3435
                if (s->nb_streams == feed->nb_streams) {
3436
                    matches = 1;
3437
                    for(i=0;i<s->nb_streams;i++) {
3438
                        AVStream *sf, *ss;
3439
                        sf = feed->streams[i];
3440
                        ss = s->streams[i];
3441

    
3442
                        if (sf->index != ss->index ||
3443
                            sf->id != ss->id) {
3444
                            printf("Index & Id do not match for stream %d (%s)\n",
3445
                                   i, feed->feed_filename);
3446
                            matches = 0;
3447
                        } else {
3448
                            AVCodecContext *ccf, *ccs;
3449

    
3450
                            ccf = sf->codec;
3451
                            ccs = ss->codec;
3452
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3453

    
3454
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3455
                                printf("Codecs do not match for stream %d\n", i);
3456
                                matches = 0;
3457
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3458
                                printf("Codec bitrates do not match for stream %d\n", i);
3459
                                matches = 0;
3460
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3461
                                if (CHECK_CODEC(time_base.den) ||
3462
                                    CHECK_CODEC(time_base.num) ||
3463
                                    CHECK_CODEC(width) ||
3464
                                    CHECK_CODEC(height)) {
3465
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3466
                                    matches = 0;
3467
                                }
3468
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3469
                                if (CHECK_CODEC(sample_rate) ||
3470
                                    CHECK_CODEC(channels) ||
3471
                                    CHECK_CODEC(frame_size)) {
3472
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3473
                                    matches = 0;
3474
                                }
3475
                            } else {
3476
                                printf("Unknown codec type\n");
3477
                                matches = 0;
3478
                            }
3479
                        }
3480
                        if (!matches) {
3481
                            break;
3482
                        }
3483
                    }
3484
                } else {
3485
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3486
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3487
                }
3488

    
3489
                av_close_input_file(s);
3490
            } else {
3491
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3492
                        feed->feed_filename);
3493
            }
3494
            if (!matches) {
3495
                if (feed->readonly) {
3496
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3497
                        feed->feed_filename);
3498
                    exit(1);
3499
                }
3500
                unlink(feed->feed_filename);
3501
            }
3502
        }
3503
        if (!url_exist(feed->feed_filename)) {
3504
            AVFormatContext s1, *s = &s1;
3505

    
3506
            if (feed->readonly) {
3507
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3508
                    feed->feed_filename);
3509
                exit(1);
3510
            }
3511

    
3512
            /* only write the header of the ffm file */
3513
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3514
                fprintf(stderr, "Could not open output feed file '%s'\n",
3515
                        feed->feed_filename);
3516
                exit(1);
3517
            }
3518
            s->oformat = feed->fmt;
3519
            s->nb_streams = feed->nb_streams;
3520
            for(i=0;i<s->nb_streams;i++) {
3521
                AVStream *st;
3522
                st = feed->streams[i];
3523
                s->streams[i] = st;
3524
            }
3525
            av_set_parameters(s, NULL);
3526
            av_write_header(s);
3527
            /* XXX: need better api */
3528
            av_freep(&s->priv_data);
3529
            url_fclose(&s->pb);
3530
        }
3531
        /* get feed size and write index */
3532
        fd = open(feed->feed_filename, O_RDONLY);
3533
        if (fd < 0) {
3534
            fprintf(stderr, "Could not open output feed file '%s'\n",
3535
                    feed->feed_filename);
3536
            exit(1);
3537
        }
3538

    
3539
        feed->feed_write_index = ffm_read_write_index(fd);
3540
        feed->feed_size = lseek(fd, 0, SEEK_END);
3541
        /* ensure that we do not wrap before the end of file */
3542
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3543
            feed->feed_max_size = feed->feed_size;
3544

    
3545
        close(fd);
3546
    }
3547
}
3548

    
3549
/* compute the bandwidth used by each stream */
3550
static void compute_bandwidth(void)
3551
{
3552
    int bandwidth, i;
3553
    FFStream *stream;
3554

    
3555
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3556
        bandwidth = 0;
3557
        for(i=0;i<stream->nb_streams;i++) {
3558
            AVStream *st = stream->streams[i];
3559
            switch(st->codec->codec_type) {
3560
            case CODEC_TYPE_AUDIO:
3561
            case CODEC_TYPE_VIDEO:
3562
                bandwidth += st->codec->bit_rate;
3563
                break;
3564
            default:
3565
                break;
3566
            }
3567
        }
3568
        stream->bandwidth = (bandwidth + 999) / 1000;
3569
    }
3570
}
3571

    
3572
static void get_arg(char *buf, int buf_size, const char **pp)
3573
{
3574
    const char *p;
3575
    char *q;
3576
    int quote;
3577

    
3578
    p = *pp;
3579
    while (isspace(*p)) p++;
3580
    q = buf;
3581
    quote = 0;
3582
    if (*p == '\"' || *p == '\'')
3583
        quote = *p++;
3584
    for(;;) {
3585
        if (quote) {
3586
            if (*p == quote)
3587
                break;
3588
        } else {
3589
            if (isspace(*p))
3590
                break;
3591
        }
3592
        if (*p == '\0')
3593
            break;
3594
        if ((q - buf) < buf_size - 1)
3595
            *q++ = *p;
3596
        p++;
3597
    }
3598
    *q = '\0';
3599
    if (quote && *p == quote)
3600
        p++;
3601
    *pp = p;
3602
}
3603

    
3604
/* add a codec and set the default parameters */
3605
static void add_codec(FFStream *stream, AVCodecContext *av)
3606
{
3607
    AVStream *st;
3608

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

    
3642
        if (!av->nsse_weight)
3643
            av->nsse_weight = 8;
3644

    
3645
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3646
        av->me_method = ME_EPZS;
3647
        av->rc_buffer_aggressivity = 1.0;
3648

    
3649
        if (!av->rc_eq)
3650
            av->rc_eq = "tex^qComp";
3651
        if (!av->i_quant_factor)
3652
            av->i_quant_factor = -0.8;
3653
        if (!av->b_quant_factor)
3654
            av->b_quant_factor = 1.25;
3655
        if (!av->b_quant_offset)
3656
            av->b_quant_offset = 1.25;
3657
        if (!av->rc_max_rate)
3658
            av->rc_max_rate = av->bit_rate * 2;
3659

    
3660
        if (av->rc_max_rate && !av->rc_buffer_size) {
3661
            av->rc_buffer_size = av->rc_max_rate;
3662
        }
3663

    
3664

    
3665
        break;
3666
    default:
3667
        av_abort();
3668
    }
3669

    
3670
    st = av_mallocz(sizeof(AVStream));
3671
    if (!st)
3672
        return;
3673
    st->codec = avcodec_alloc_context();
3674
    stream->streams[stream->nb_streams++] = st;
3675
    memcpy(st->codec, av, sizeof(AVCodecContext));
3676
}
3677

    
3678
static int opt_audio_codec(const char *arg)
3679
{
3680
    AVCodec *p;
3681

    
3682
    p = first_avcodec;
3683
    while (p) {
3684
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3685
            break;
3686
        p = p->next;
3687
    }
3688
    if (p == NULL) {
3689
        return CODEC_ID_NONE;
3690
    }
3691

    
3692
    return p->id;
3693
}
3694

    
3695
static int opt_video_codec(const char *arg)
3696
{
3697
    AVCodec *p;
3698

    
3699
    p = first_avcodec;
3700
    while (p) {
3701
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3702
            break;
3703
        p = p->next;
3704
    }
3705
    if (p == NULL) {
3706
        return CODEC_ID_NONE;
3707
    }
3708

    
3709
    return p->id;
3710
}
3711

    
3712
/* simplistic plugin support */
3713

    
3714
#ifdef CONFIG_HAVE_DLOPEN
3715
void load_module(const char *filename)
3716
{
3717
    void *dll;
3718
    void (*init_func)(void);
3719
    dll = dlopen(filename, RTLD_NOW);
3720
    if (!dll) {
3721
        fprintf(stderr, "Could not load module '%s' - %s\n",
3722
                filename, dlerror());
3723
        return;
3724
    }
3725

    
3726
    init_func = dlsym(dll, "ffserver_module_init");
3727
    if (!init_func) {
3728
        fprintf(stderr,
3729
                "%s: init function 'ffserver_module_init()' not found\n",
3730
                filename);
3731
        dlclose(dll);
3732
    }
3733

    
3734
    init_func();
3735
}
3736
#endif
3737

    
3738
static int parse_ffconfig(const char *filename)
3739
{
3740
    FILE *f;
3741
    char line[1024];
3742
    char cmd[64];
3743
    char arg[1024];
3744
    const char *p;
3745
    int val, errors, line_num;
3746
    FFStream **last_stream, *stream, *redirect;
3747
    FFStream **last_feed, *feed;
3748
    AVCodecContext audio_enc, video_enc;
3749
    int audio_id, video_id;
3750

    
3751
    f = fopen(filename, "r");
3752
    if (!f) {
3753
        perror(filename);
3754
        return -1;
3755
    }
3756

    
3757
    errors = 0;
3758
    line_num = 0;
3759
    first_stream = NULL;
3760
    last_stream = &first_stream;
3761
    first_feed = NULL;
3762
    last_feed = &first_feed;
3763
    stream = NULL;
3764
    feed = NULL;
3765
    redirect = NULL;
3766
    audio_id = CODEC_ID_NONE;
3767
    video_id = CODEC_ID_NONE;
3768
    for(;;) {
3769
        if (fgets(line, sizeof(line), f) == NULL)
3770
            break;
3771
        line_num++;
3772
        p = line;
3773
        while (isspace(*p))
3774
            p++;
3775
        if (*p == '\0' || *p == '#')
3776
            continue;
3777

    
3778
        get_arg(cmd, sizeof(cmd), &p);
3779

    
3780
        if (!strcasecmp(cmd, "Port")) {
3781
            get_arg(arg, sizeof(arg), &p);
3782
            my_http_addr.sin_port = htons (atoi(arg));
3783
        } else if (!strcasecmp(cmd, "BindAddress")) {
3784
            get_arg(arg, sizeof(arg), &p);
3785
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3786
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3787
                        filename, line_num, arg);
3788
                errors++;
3789
            }
3790
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3791
            ffserver_daemon = 0;
3792
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3793
            get_arg(arg, sizeof(arg), &p);
3794
            my_rtsp_addr.sin_port = htons (atoi(arg));
3795
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3796
            get_arg(arg, sizeof(arg), &p);
3797
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3798
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3799
                        filename, line_num, arg);
3800
                errors++;
3801
            }
3802
        } else if (!strcasecmp(cmd, "MaxClients")) {
3803
            get_arg(arg, sizeof(arg), &p);
3804
            val = atoi(arg);
3805
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3806
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3807
                        filename, line_num, arg);
3808
                errors++;
3809
            } else {
3810
                nb_max_connections = val;
3811
            }
3812
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3813
            get_arg(arg, sizeof(arg), &p);
3814
            val = atoi(arg);
3815
            if (val < 10 || val > 100000) {
3816
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3817
                        filename, line_num, arg);
3818
                errors++;
3819
            } else {
3820
                max_bandwidth = val;
3821
            }
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
                    char argbuf[256];
3860

    
3861
                    get_arg(argbuf, sizeof(argbuf), &p);
3862
                    if (!argbuf[0])
3863
                        break;
3864

    
3865
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3866
                    strcpy(feed->child_argv[i], argbuf);
3867
                }
3868

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

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

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

    
3904
                get_arg(arg, sizeof(arg), &p);
3905
                p1 = arg;
3906
                fsize = strtod(p1, (char **)&p1);
3907
                switch(toupper(*p1)) {
3908
                case 'K':
3909
                    fsize *= 1024;
3910
                    break;
3911
                case 'M':
3912
                    fsize *= 1024 * 1024;
3913
                    break;
3914
                case 'G':
3915
                    fsize *= 1024 * 1024 * 1024;
3916
                    break;
3917
                }
3918
                feed->feed_max_size = (int64_t)fsize;
3919
            }
3920
        } else if (!strcasecmp(cmd, "</Feed>")) {
3921
            if (!feed) {
3922
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3923
                        filename, line_num);
3924
                errors++;
3925
#if 0
3926
            } else {
3927
                /* Make sure that we start out clean */
3928
                if (unlink(feed->feed_filename) < 0
3929
                    && errno != ENOENT) {
3930
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3931
                        filename, line_num, feed->feed_filename, strerror(errno));
3932
                    errors++;
3933
                }
3934
#endif
3935
            }
3936
            feed = NULL;
3937
        } else if (!strcasecmp(cmd, "<Stream")) {
3938
            /*********************************************/
3939
            /* Stream related options */
3940
            char *q;
3941
            if (stream || feed) {
3942
                fprintf(stderr, "%s:%d: Already in a tag\n",
3943
                        filename, line_num);
3944
            } else {
3945
                stream = av_mallocz(sizeof(FFStream));
3946
                *last_stream = stream;
3947
                last_stream = &stream->next;
3948

    
3949
                get_arg(stream->filename, sizeof(stream->filename), &p);
3950
                q = strrchr(stream->filename, '>');
3951
                if (*q)
3952
                    *q = '\0';
3953
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3954
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3955
                memset(&video_enc, 0, sizeof(AVCodecContext));
3956
                audio_id = CODEC_ID_NONE;
3957
                video_id = CODEC_ID_NONE;
3958
                if (stream->fmt) {
3959
                    audio_id = stream->fmt->audio_codec;
3960
                    video_id = stream->fmt->video_codec;
3961
                }
3962
            }
3963
        } else if (!strcasecmp(cmd, "Feed")) {
3964
            get_arg(arg, sizeof(arg), &p);
3965
            if (stream) {
3966
                FFStream *sfeed;
3967

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

    
4086
                get_arg(arg, sizeof(arg), &p);
4087

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

    
4215
            get_arg(arg, sizeof(arg), &p);
4216
            if (strcasecmp(arg, "allow") == 0) {
4217
                acl.action = IP_ALLOW;
4218
            } else if (strcasecmp(arg, "deny") == 0) {
4219
                acl.action = IP_DENY;
4220
            } else {
4221
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4222
                        filename, line_num, arg);
4223
                errors++;
4224
            }
4225

    
4226
            get_arg(arg, sizeof(arg), &p);
4227

    
4228
            he = gethostbyname(arg);
4229
            if (!he) {
4230
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4231
                        filename, line_num, arg);
4232
                errors++;
4233
            } else {
4234
                /* Only take the first */
4235
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4236
                acl.last = acl.first;
4237
            }
4238

    
4239
            get_arg(arg, sizeof(arg), &p);
4240

    
4241
            if (arg[0]) {
4242
                he = gethostbyname(arg);
4243
                if (!he) {
4244
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4245
                            filename, line_num, arg);
4246
                    errors++;
4247
                } else {
4248
                    /* Only take the first */
4249
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4250
                }
4251
            }
4252

    
4253
            if (!errors) {
4254
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4255
                IPAddressACL **naclp = 0;
4256

    
4257
                *nacl = acl;
4258
                nacl->next = 0;
4259

    
4260
                if (stream) {
4261
                    naclp = &stream->acl;
4262
                } else if (feed) {
4263
                    naclp = &feed->acl;
4264
                } else {
4265
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4266
                            filename, line_num);
4267
                    errors++;
4268
                }
4269

    
4270
                if (naclp) {
4271
                    while (*naclp)
4272
                        naclp = &(*naclp)->next;
4273

    
4274
                    *naclp = nacl;
4275
                }
4276
            }
4277
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4278
            get_arg(arg, sizeof(arg), &p);
4279
            if (stream) {
4280
                av_freep(&stream->rtsp_option);
4281
                /* XXX: av_strdup ? */
4282
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4283
                if (stream->rtsp_option) {
4284
                    strcpy(stream->rtsp_option, arg);
4285
                }
4286
            }
4287
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4288
            get_arg(arg, sizeof(arg), &p);
4289
            if (stream) {
4290
                if (!inet_aton(arg, &stream->multicast_ip)) {
4291
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
4292
                            filename, line_num, arg);
4293
                    errors++;
4294
                }
4295
                stream->is_multicast = 1;
4296
                stream->loop = 1; /* default is looping */
4297
            }
4298
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4299
            get_arg(arg, sizeof(arg), &p);
4300
            if (stream) {
4301
                stream->multicast_port = atoi(arg);
4302
            }
4303
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4304
            get_arg(arg, sizeof(arg), &p);
4305
            if (stream) {
4306
                stream->multicast_ttl = atoi(arg);
4307
            }
4308
        } else if (!strcasecmp(cmd, "NoLoop")) {
4309
            if (stream) {
4310
                stream->loop = 0;
4311
            }
4312
        } else if (!strcasecmp(cmd, "</Stream>")) {
4313
            if (!stream) {
4314
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4315
                        filename, line_num);
4316
                errors++;
4317
            }
4318
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4319
                if (audio_id != CODEC_ID_NONE) {
4320
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4321
                    audio_enc.codec_id = audio_id;
4322
                    add_codec(stream, &audio_enc);
4323
                }
4324
                if (video_id != CODEC_ID_NONE) {
4325
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4326
                    video_enc.codec_id = video_id;
4327
                    add_codec(stream, &video_enc);
4328
                }
4329
            }
4330
            stream = NULL;
4331
        } else if (!strcasecmp(cmd, "<Redirect")) {
4332
            /*********************************************/
4333
            char *q;
4334
            if (stream || feed || redirect) {
4335
                fprintf(stderr, "%s:%d: Already in a tag\n",
4336
                        filename, line_num);
4337
                errors++;
4338
            } else {
4339
                redirect = av_mallocz(sizeof(FFStream));
4340
                *last_stream = redirect;
4341
                last_stream = &redirect->next;
4342

    
4343
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4344
                q = strrchr(redirect->filename, '>');
4345
                if (*q)
4346
                    *q = '\0';
4347
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4348
            }
4349
        } else if (!strcasecmp(cmd, "URL")) {
4350
            if (redirect) {
4351
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4352
            }
4353
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4354
            if (!redirect) {
4355
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4356
                        filename, line_num);
4357
                errors++;
4358
            }
4359
            if (!redirect->feed_filename[0]) {
4360
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4361
                        filename, line_num);
4362
                errors++;
4363
            }
4364
            redirect = NULL;
4365
        } else if (!strcasecmp(cmd, "LoadModule")) {
4366
            get_arg(arg, sizeof(arg), &p);
4367
#ifdef CONFIG_HAVE_DLOPEN
4368
            load_module(arg);
4369
#else
4370
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4371
                    filename, line_num, arg);
4372
            errors++;
4373
#endif
4374
        } else {
4375
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4376
                    filename, line_num, cmd);
4377
            errors++;
4378
        }
4379
    }
4380

    
4381
    fclose(f);
4382
    if (errors)
4383
        return -1;
4384
    else
4385
        return 0;
4386
}
4387

    
4388

    
4389
#if 0
4390
static void write_packet(FFCodec *ffenc,
4391
                         uint8_t *buf, int size)
4392
{
4393
    PacketHeader hdr;
4394
    AVCodecContext *enc = &ffenc->enc;
4395
    uint8_t *wptr;
4396
    mk_header(&hdr, enc, size);
4397
    wptr = http_fifo.wptr;
4398
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4399
    fifo_write(&http_fifo, buf, size, &wptr);
4400
    /* atomic modification of wptr */
4401
    http_fifo.wptr = wptr;
4402
    ffenc->data_count += size;
4403
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4404
}
4405
#endif
4406

    
4407
static void show_banner(void)
4408
{
4409
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4410
}
4411

    
4412
static void show_help(void)
4413
{
4414
    show_banner();
4415
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4416
           "Hyper fast multi format Audio/Video streaming server\n"
4417
           "\n"
4418
           "-L            : print the LICENSE\n"
4419
           "-h            : this help\n"
4420
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4421
           );
4422
}
4423

    
4424
static void show_license(void)
4425
{
4426
    show_banner();
4427
    printf(
4428
    "This library is free software; you can redistribute it and/or\n"
4429
    "modify it under the terms of the GNU Lesser General Public\n"
4430
    "License as published by the Free Software Foundation; either\n"
4431
    "version 2 of the License, or (at your option) any later version.\n"
4432
    "\n"
4433
    "This library is distributed in the hope that it will be useful,\n"
4434
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4435
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4436
    "Lesser General Public License for more details.\n"
4437
    "\n"
4438
    "You should have received a copy of the GNU Lesser General Public\n"
4439
    "License along with this library; if not, write to the Free Software\n"
4440
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4441
    );
4442
}
4443

    
4444
static void handle_child_exit(int sig)
4445
{
4446
    pid_t pid;
4447
    int status;
4448

    
4449
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4450
        FFStream *feed;
4451

    
4452
        for (feed = first_feed; feed; feed = feed->next) {
4453
            if (feed->pid == pid) {
4454
                int uptime = time(0) - feed->pid_start;
4455

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

    
4459
                if (uptime < 30) {
4460
                    /* Turn off any more restarts */
4461
                    feed->child_argv = 0;
4462
                }
4463
            }
4464
        }
4465
    }
4466

    
4467
    need_to_start_children = 1;
4468
}
4469

    
4470
int main(int argc, char **argv)
4471
{
4472
    const char *config_filename;
4473
    int c;
4474
    struct sigaction sigact;
4475

    
4476
    av_register_all();
4477

    
4478
    config_filename = "/etc/ffserver.conf";
4479

    
4480
    my_program_name = argv[0];
4481
    my_program_dir = getcwd(0, 0);
4482
    ffserver_daemon = 1;
4483

    
4484
    for(;;) {
4485
        c = getopt(argc, argv, "ndLh?f:");
4486
        if (c == -1)
4487
            break;
4488
        switch(c) {
4489
        case 'L':
4490
            show_license();
4491
            exit(1);
4492
        case '?':
4493
        case 'h':
4494
            show_help();
4495
            exit(1);
4496
        case 'n':
4497
            no_launch = 1;
4498
            break;
4499
        case 'd':
4500
            ffserver_debug = 1;
4501
            ffserver_daemon = 0;
4502
            break;
4503
        case 'f':
4504
            config_filename = optarg;
4505
            break;
4506
        default:
4507
            exit(2);
4508
        }
4509
    }
4510

    
4511
    putenv("http_proxy");               /* Kill the http_proxy */
4512

    
4513
    srandom(gettime_ms() + (getpid() << 16));
4514

    
4515
    /* address on which the server will handle HTTP connections */
4516
    my_http_addr.sin_family = AF_INET;
4517
    my_http_addr.sin_port = htons (8080);
4518
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4519

    
4520
    /* address on which the server will handle RTSP connections */
4521
    my_rtsp_addr.sin_family = AF_INET;
4522
    my_rtsp_addr.sin_port = htons (5454);
4523
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4524

    
4525
    nb_max_connections = 5;
4526
    max_bandwidth = 1000;
4527
    first_stream = NULL;
4528
    logfilename[0] = '\0';
4529

    
4530
    memset(&sigact, 0, sizeof(sigact));
4531
    sigact.sa_handler = handle_child_exit;
4532
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4533
    sigaction(SIGCHLD, &sigact, 0);
4534

    
4535
    if (parse_ffconfig(config_filename) < 0) {
4536
        fprintf(stderr, "Incorrect config file - exiting.\n");
4537
        exit(1);
4538
    }
4539

    
4540
    build_file_streams();
4541

    
4542
    build_feed_streams();
4543

    
4544
    compute_bandwidth();
4545

    
4546
    /* put the process in background and detach it from its TTY */
4547
    if (ffserver_daemon) {
4548
        int pid;
4549

    
4550
        pid = fork();
4551
        if (pid < 0) {
4552
            perror("fork");
4553
            exit(1);
4554
        } else if (pid > 0) {
4555
            /* parent : exit */
4556
            exit(0);
4557
        } else {
4558
            /* child */
4559
            setsid();
4560
            chdir("/");
4561
            close(0);
4562
            open("/dev/null", O_RDWR);
4563
            if (strcmp(logfilename, "-") != 0) {
4564
                close(1);
4565
                dup(0);
4566
            }
4567
            close(2);
4568
            dup(0);
4569
        }
4570
    }
4571

    
4572
    /* signal init */
4573
    signal(SIGPIPE, SIG_IGN);
4574

    
4575
    /* open log file if needed */
4576
    if (logfilename[0] != '\0') {
4577
        if (!strcmp(logfilename, "-"))
4578
            logfile = stdout;
4579
        else
4580
            logfile = fopen(logfilename, "w");
4581
    }
4582

    
4583
    if (http_server() < 0) {
4584
        fprintf(stderr, "Could not start server\n");
4585
        exit(1);
4586
    }
4587

    
4588
    return 0;
4589
}