Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 33a4ecbe

History | View | Annotate | Download (152 KB)

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

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

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

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

    
53
#undef exit
54

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

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

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

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

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

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

    
89
#define IOBUFFER_INIT_SIZE 8192
90

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

    
95
#define SYNC_TIMEOUT (10 * 1000)
96

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

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

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

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

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

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

    
165
static AVFrame dummy_frame;
166

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
289
static int nb_max_connections;
290
static int nb_connections;
291

    
292
static int max_bandwidth;
293
static int current_bandwidth;
294

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

    
297
static AVRandomState random_state;
298

    
299
static FILE *logfile = NULL;
300

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

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

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

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

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

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

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

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

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

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

    
362

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

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

    
372
            feed->pid = fork();
373

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

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

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

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

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

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

    
411
                signal(SIGPIPE, SIG_DFL);
412

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

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

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

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

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

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

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

    
450
    return server_fd;
451
}
452

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

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

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

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

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

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

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

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

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

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

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

    
525
    start_children(first_feed);
526

    
527
    first_http_ctx = NULL;
528
    nb_connections = 0;
529

    
530
    start_multicast();
531

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

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

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

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

    
601
        cur_time = av_gettime() / 1000;
602

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

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

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

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

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

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

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

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

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

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

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

    
681
    start_wait_request(c, is_rtsp);
682

    
683
    return;
684

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

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

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

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

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

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

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

    
749
    ctx = &c->fmt_ctx;
750

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
973
                q += 20;
974

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

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

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

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

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

    
1000
        p++;
1001
    }
1002

    
1003
    return 0;
1004
}
1005

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

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

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

    
1022
        /* Potential stream */
1023

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

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

    
1041
    return best;
1042
}
1043

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

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

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

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

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

    
1079
    return action_required;
1080
}
1081

    
1082

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1238
        p++;
1239
    }
1240

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

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

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

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

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

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

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

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

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

    
1317
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1318
        c->http_error = 200;
1319
        q = c->buffer;
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1322
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1323
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1324
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1325
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1326
            current_bandwidth, max_bandwidth);
1327
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1328

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

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

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

    
1348
            p++;
1349
        }
1350

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

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

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

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

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

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

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

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

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

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

    
1456
    stream->conns_served++;
1457

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

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

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

    
1481
                p++;
1482
            }
1483

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

    
1487
                logline += 17;
1488

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

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

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

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

    
1510
                if (wmpc) {
1511
                    if (modify_current_stream(wmpc, ratebuf)) {
1512
                        wmpc->switch_pending = 1;
1513
                    }
1514
                }
1515
            }
1516

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

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

    
1536
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1537
        goto send_stats;
1538

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

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

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

    
1557
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1558

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

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

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

    
1594
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1595
{
1596
    static const char *suffix = " kMGTP";
1597
    const char *s;
1598

    
1599
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1600
    }
1601

    
1602
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1603
}
1604

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

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

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

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

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

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

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

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

    
1734
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1735
                {
1736
                    FILE *pid_stat;
1737
                    char ps_cmd[64];
1738

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

    
1744
                    pid_stat = popen(ps_cmd, "r");
1745
                    if (pid_stat) {
1746
                        char cpuperc[10];
1747
                        char cpuused[64];
1748

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

    
1759
                url_fprintf(pb, "<p>");
1760
            }
1761
            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");
1762

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

    
1769
                parameters[0] = 0;
1770

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

    
1789
        }
1790
        stream = stream->next;
1791
    }
1792

    
1793
#if 0
1794
    {
1795
        float avg;
1796
        AVCodecContext *enc;
1797
        char buf[1024];
1798

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

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

    
1823
    /* connection status */
1824
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1825

    
1826
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1827
                 nb_connections, nb_max_connections);
1828

    
1829
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1830
                 current_bandwidth, max_bandwidth);
1831

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

    
1840
        bitrate = 0;
1841
        if (c1->stream) {
1842
            for (j = 0; j < c1->stream->nb_streams; j++) {
1843
                if (!c1->stream->feed) {
1844
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1845
                } else {
1846
                    if (c1->feed_streams[j] >= 0) {
1847
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1848
                    }
1849
                }
1850
            }
1851
        }
1852

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

    
1872
    /* date */
1873
    ti = time(NULL);
1874
    p = ctime(&ti);
1875
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1876
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1877

    
1878
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1879
    c->buffer_ptr = c->pb_buffer;
1880
    c->buffer_end = c->pb_buffer + len;
1881
}
1882

    
1883
/* check if the parser needs to be opened for stream i */
1884
static void open_parser(AVFormatContext *s, int i)
1885
{
1886
    AVStream *st = s->streams[i];
1887
    AVCodec *codec;
1888

    
1889
    if (!st->codec->codec) {
1890
        codec = avcodec_find_decoder(st->codec->codec_id);
1891
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1892
            st->codec->parse_only = 1;
1893
            if (avcodec_open(st->codec, codec) < 0) {
1894
                st->codec->parse_only = 0;
1895
            }
1896
        }
1897
    }
1898
}
1899

    
1900
static int open_input_stream(HTTPContext *c, const char *info)
1901
{
1902
    char buf[128];
1903
    char input_filename[1024];
1904
    AVFormatContext *s;
1905
    int buf_size, i;
1906
    int64_t stream_pos;
1907

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

    
1934
#if 0
1935
    { time_t when = stream_pos / 1000000;
1936
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1937
    }
1938
#endif
1939

    
1940
    /* open stream */
1941
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1942
                           buf_size, c->stream->ap_in) < 0) {
1943
        http_log("%s not found", input_filename);
1944
        return -1;
1945
    }
1946
    c->fmt_in = s;
1947

    
1948
    /* open each parser */
1949
    for(i=0;i<s->nb_streams;i++)
1950
        open_parser(s, i);
1951

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

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

    
1973
/* return the server clock (in us) */
1974
static int64_t get_server_clock(HTTPContext *c)
1975
{
1976
    /* compute current pts value from system time */
1977
    return (cur_time - c->start_time) * 1000;
1978
}
1979

    
1980
/* return the estimated time at which the current packet must be sent
1981
   (in us) */
1982
static int64_t get_packet_send_clock(HTTPContext *c)
1983
{
1984
    int bytes_left, bytes_sent, frame_bytes;
1985

    
1986
    frame_bytes = c->cur_frame_bytes;
1987
    if (frame_bytes <= 0) {
1988
        return c->cur_pts;
1989
    } else {
1990
        bytes_left = c->buffer_end - c->buffer_ptr;
1991
        bytes_sent = frame_bytes - bytes_left;
1992
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1993
    }
1994
}
1995

    
1996

    
1997
static int http_prepare_data(HTTPContext *c)
1998
{
1999
    int i, len, ret;
2000
    AVFormatContext *ctx;
2001

    
2002
    av_freep(&c->pb_buffer);
2003
    switch(c->state) {
2004
    case HTTPSTATE_SEND_DATA_HEADER:
2005
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2006
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
2007
                   sizeof(c->fmt_ctx.author));
2008
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2009
                   sizeof(c->fmt_ctx.comment));
2010
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2011
                   sizeof(c->fmt_ctx.copyright));
2012
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2013
                   sizeof(c->fmt_ctx.title));
2014

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

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

    
2042
        /* prepare header and save header data in a stream */
2043
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2044
            /* XXX: potential leak */
2045
            return -1;
2046
        }
2047
        c->fmt_ctx.pb.is_streamed = 1;
2048

    
2049
        av_set_parameters(&c->fmt_ctx, NULL);
2050
        if (av_write_header(&c->fmt_ctx) < 0)
2051
            return -1;
2052

    
2053
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2054
        c->buffer_ptr = c->pb_buffer;
2055
        c->buffer_end = c->pb_buffer + len;
2056

    
2057
        c->state = HTTPSTATE_SEND_DATA;
2058
        c->last_packet_sent = 0;
2059
        break;
2060
    case HTTPSTATE_SEND_DATA:
2061
        /* find a new packet */
2062
        {
2063
            AVPacket pkt;
2064

    
2065
            /* read a packet from the input stream */
2066
            if (c->stream->feed) {
2067
                ffm_set_write_index(c->fmt_in,
2068
                                    c->stream->feed->feed_write_index,
2069
                                    c->stream->feed->feed_size);
2070
            }
2071

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

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

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

    
2204
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2205
                        c->cur_frame_bytes = len;
2206
                        c->buffer_ptr = c->pb_buffer;
2207
                        c->buffer_end = c->pb_buffer + len;
2208

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

    
2234
        c->last_packet_sent = 1;
2235
        break;
2236
    }
2237
    return 0;
2238
}
2239

    
2240
/* should convert the format at the same time */
2241
/* send data starting at c->buffer_ptr to the output connection
2242
   (either UDP or TCP connection) */
2243
static int http_send_data(HTTPContext *c)
2244
{
2245
    int len, ret;
2246

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

    
2277
                c->data_count += len;
2278
                update_datarate(&c->datarate, c->data_count);
2279
                if (c->stream)
2280
                    c->stream->bytes_served += len;
2281

    
2282
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2283
                    /* RTP packets are sent inside the RTSP TCP connection */
2284
                    ByteIOContext pb1, *pb = &pb1;
2285
                    int interleaved_index, size;
2286
                    uint8_t header[4];
2287
                    HTTPContext *rtsp_c;
2288

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

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

    
2367
static int http_start_receive_data(HTTPContext *c)
2368
{
2369
    int fd;
2370

    
2371
    if (c->stream->feed_opened)
2372
        return -1;
2373

    
2374
    /* Don't permit writing to this one */
2375
    if (c->stream->readonly)
2376
        return -1;
2377

    
2378
    /* open feed */
2379
    fd = open(c->stream->feed_filename, O_RDWR);
2380
    if (fd < 0)
2381
        return -1;
2382
    c->feed_fd = fd;
2383

    
2384
    c->stream->feed_write_index = ffm_read_write_index(fd);
2385
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2386
    lseek(fd, 0, SEEK_SET);
2387

    
2388
    /* init buffer input */
2389
    c->buffer_ptr = c->buffer;
2390
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2391
    c->stream->feed_opened = 1;
2392
    return 0;
2393
}
2394

    
2395
static int http_receive_data(HTTPContext *c)
2396
{
2397
    HTTPContext *c1;
2398

    
2399
    if (c->buffer_end > c->buffer_ptr) {
2400
        int len;
2401

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

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

    
2427
    if (c->buffer_ptr >= c->buffer_end) {
2428
        FFStream *feed = c->stream;
2429
        /* a packet has been received : write it in the store, except
2430
           if header */
2431
        if (c->data_count > FFM_PACKET_SIZE) {
2432

    
2433
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2434
            /* XXX: use llseek or url_seek */
2435
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2436
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2437

    
2438
            feed->feed_write_index += FFM_PACKET_SIZE;
2439
            /* update file size */
2440
            if (feed->feed_write_index > c->stream->feed_size)
2441
                feed->feed_size = feed->feed_write_index;
2442

    
2443
            /* handle wrap around if max file size reached */
2444
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2445
                feed->feed_write_index = FFM_PACKET_SIZE;
2446

    
2447
            /* write index */
2448
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2449

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

    
2464
            memset(&s, 0, sizeof(s));
2465

    
2466
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2467
            pb->buf_end = c->buffer_end;        /* ?? */
2468
            pb->is_streamed = 1;
2469

    
2470
            /* use feed output format name to find corresponding input format */
2471
            fmt_in = av_find_input_format(feed->fmt->name);
2472
            if (!fmt_in)
2473
                goto fail;
2474

    
2475
            if (fmt_in->priv_data_size > 0) {
2476
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2477
                if (!s.priv_data)
2478
                    goto fail;
2479
            } else
2480
                s.priv_data = NULL;
2481

    
2482
            if (fmt_in->read_header(&s, 0) < 0) {
2483
                av_freep(&s.priv_data);
2484
                goto fail;
2485
            }
2486

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

    
2501
    return 0;
2502
 fail:
2503
    c->stream->feed_opened = 0;
2504
    close(c->feed_fd);
2505
    return -1;
2506
}
2507

    
2508
/********************************************************************/
2509
/* RTSP handling */
2510

    
2511
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2512
{
2513
    const char *str;
2514
    time_t ti;
2515
    char *p;
2516
    char buf2[32];
2517

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

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

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

    
2570
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2571
{
2572
    rtsp_reply_header(c, error_number);
2573
    url_fprintf(c->pb, "\r\n");
2574
}
2575

    
2576
static int rtsp_parse_request(HTTPContext *c)
2577
{
2578
    const char *p, *p1, *p2;
2579
    char cmd[32];
2580
    char url[1024];
2581
    char protocol[32];
2582
    char line[1024];
2583
    ByteIOContext pb1;
2584
    int len;
2585
    RTSPHeader header1, *header = &header1;
2586

    
2587
    c->buffer_ptr[0] = '\0';
2588
    p = c->buffer;
2589

    
2590
    get_word(cmd, sizeof(cmd), &p);
2591
    get_word(url, sizeof(url), &p);
2592
    get_word(protocol, sizeof(protocol), &p);
2593

    
2594
    av_strlcpy(c->method, cmd, sizeof(c->method));
2595
    av_strlcpy(c->url, url, sizeof(c->url));
2596
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2597

    
2598
    c->pb = &pb1;
2599
    if (url_open_dyn_buf(c->pb) < 0) {
2600
        /* XXX: cannot do more */
2601
        c->pb = NULL; /* safety */
2602
        return -1;
2603
    }
2604

    
2605
    /* check version name */
2606
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2607
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2608
        goto the_end;
2609
    }
2610

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

    
2637
    /* handle sequence number */
2638
    c->seq = header->seq;
2639

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

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

    
2678
    if (url_open_dyn_buf(pb) < 0)
2679
        return -1;
2680

    
2681
    /* general media info */
2682

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

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

    
2768
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2769
{
2770
    FFStream *stream;
2771
    char path1[1024];
2772
    const char *path;
2773
    uint8_t *content;
2774
    int content_length, len;
2775
    struct sockaddr_in my_addr;
2776

    
2777
    /* find which url is asked */
2778
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2779
    path = path1;
2780
    if (*path == '/')
2781
        path++;
2782

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

    
2793
 found:
2794
    /* prepare the media description in sdp format */
2795

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

    
2811
static HTTPContext *find_rtp_session(const char *session_id)
2812
{
2813
    HTTPContext *c;
2814

    
2815
    if (session_id[0] == '\0')
2816
        return NULL;
2817

    
2818
    for(c = first_http_ctx; c != NULL; c = c->next) {
2819
        if (!strcmp(c->session_id, session_id))
2820
            return c;
2821
    }
2822
    return NULL;
2823
}
2824

    
2825
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2826
{
2827
    RTSPTransportField *th;
2828
    int i;
2829

    
2830
    for(i=0;i<h->nb_transports;i++) {
2831
        th = &h->transports[i];
2832
        if (th->protocol == protocol)
2833
            return th;
2834
    }
2835
    return NULL;
2836
}
2837

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

    
2851
    /* find which url is asked */
2852
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2853
    path = path1;
2854
    if (*path == '/')
2855
        path++;
2856

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

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

    
2884
    /* generate session id if needed */
2885
    if (h->session_id[0] == '\0') {
2886
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2887
                 av_random(&random_state), av_random(&random_state));
2888
    }
2889

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

    
2903
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2904
                                   th->protocol);
2905
        if (!rtp_c) {
2906
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2907
            return;
2908
        }
2909

    
2910
        /* open input stream */
2911
        if (open_input_stream(rtp_c, "") < 0) {
2912
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2913
            return;
2914
        }
2915
    }
2916

    
2917
    /* test if stream is OK (test needed because several SETUP needs
2918
       to be done for a given file) */
2919
    if (rtp_c->stream != stream) {
2920
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2921
        return;
2922
    }
2923

    
2924
    /* test if stream is already set up */
2925
    if (rtp_c->rtp_ctx[stream_index]) {
2926
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2927
        return;
2928
    }
2929

    
2930
    /* check transport */
2931
    th = find_transport(h, rtp_c->rtp_protocol);
2932
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2933
                th->client_port_min <= 0)) {
2934
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2935
        return;
2936
    }
2937

    
2938
    /* setup default options */
2939
    setup.transport_option[0] = '\0';
2940
    dest_addr = rtp_c->from_addr;
2941
    dest_addr.sin_port = htons(th->client_port_min);
2942

    
2943
    /* setup stream */
2944
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2945
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2946
        return;
2947
    }
2948

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

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

    
2974

    
2975
    url_fprintf(c->pb, "\r\n");
2976
}
2977

    
2978

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

    
2990
    rtp_c = find_rtp_session(session_id);
2991
    if (!rtp_c)
2992
        return NULL;
2993

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

    
3011
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3012
{
3013
    HTTPContext *rtp_c;
3014

    
3015
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3016
    if (!rtp_c) {
3017
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3018
        return;
3019
    }
3020

    
3021
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3022
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3023
        rtp_c->state != HTTPSTATE_READY) {
3024
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3025
        return;
3026
    }
3027

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

    
3036
    rtp_c->state = HTTPSTATE_SEND_DATA;
3037

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

    
3045
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3046
{
3047
    HTTPContext *rtp_c;
3048

    
3049
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3050
    if (!rtp_c) {
3051
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3052
        return;
3053
    }
3054

    
3055
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3056
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3057
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3058
        return;
3059
    }
3060

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

    
3070
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3071
{
3072
    HTTPContext *rtp_c;
3073
    char session_id[32];
3074

    
3075
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3076
    if (!rtp_c) {
3077
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3078
        return;
3079
    }
3080

    
3081
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3082

    
3083
    /* abort the session */
3084
    close_connection(rtp_c);
3085

    
3086
    /* now everything is OK, so we can send the connection parameters */
3087
    rtsp_reply_header(c, RTSP_STATUS_OK);
3088
    /* session ID */
3089
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3090
    url_fprintf(c->pb, "\r\n");
3091
}
3092

    
3093

    
3094
/********************************************************************/
3095
/* RTP handling */
3096

    
3097
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3098
                                       FFStream *stream, const char *session_id,
3099
                                       enum RTSPProtocol rtp_protocol)
3100
{
3101
    HTTPContext *c = NULL;
3102
    const char *proto_str;
3103

    
3104
    /* XXX: should output a warning page when coming
3105
       close to the connection limit */
3106
    if (nb_connections >= nb_max_connections)
3107
        goto fail;
3108

    
3109
    /* add a new connection */
3110
    c = av_mallocz(sizeof(HTTPContext));
3111
    if (!c)
3112
        goto fail;
3113

    
3114
    c->fd = -1;
3115
    c->poll_entry = NULL;
3116
    c->from_addr = *from_addr;
3117
    c->buffer_size = IOBUFFER_INIT_SIZE;
3118
    c->buffer = av_malloc(c->buffer_size);
3119
    if (!c->buffer)
3120
        goto fail;
3121
    nb_connections++;
3122
    c->stream = stream;
3123
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3124
    c->state = HTTPSTATE_READY;
3125
    c->is_packetized = 1;
3126
    c->rtp_protocol = rtp_protocol;
3127

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

    
3146
    current_bandwidth += stream->bandwidth;
3147

    
3148
    c->next = first_http_ctx;
3149
    first_http_ctx = c;
3150
    return c;
3151

    
3152
 fail:
3153
    if (c) {
3154
        av_free(c->buffer);
3155
        av_free(c);
3156
    }
3157
    return NULL;
3158
}
3159

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

    
3175
    /* now we can open the relevant output stream */
3176
    ctx = av_alloc_format_context();
3177
    if (!ctx)
3178
        return -1;
3179
    ctx->oformat = &rtp_muxer;
3180

    
3181
    st = av_mallocz(sizeof(AVStream));
3182
    if (!st)
3183
        goto fail;
3184
    st->codec= avcodec_alloc_context();
3185
    ctx->nb_streams = 1;
3186
    ctx->streams[0] = st;
3187

    
3188
    if (!c->stream->feed ||
3189
        c->stream->feed == c->stream) {
3190
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3191
    } else {
3192
        memcpy(st,
3193
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3194
               sizeof(AVStream));
3195
    }
3196
    st->priv_data = NULL;
3197

    
3198
    /* build destination RTP address */
3199
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3200

    
3201
    switch(c->rtp_protocol) {
3202
    case RTSP_PROTOCOL_RTP_UDP:
3203
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3204
        /* RTP/UDP case */
3205

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

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

    
3234
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3235
             ipaddr, ntohs(dest_addr->sin_port),
3236
             ctime1(buf2),
3237
             c->stream->filename, stream_index, c->protocol);
3238

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

    
3255
    c->rtp_ctx[stream_index] = ctx;
3256
    return 0;
3257
}
3258

    
3259
/********************************************************************/
3260
/* ffserver initialization */
3261

    
3262
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3263
{
3264
    AVStream *fst;
3265

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

    
3279
/* return the stream number in the feed */
3280
static int add_av_stream(FFStream *feed, AVStream *st)
3281
{
3282
    AVStream *fst;
3283
    AVCodecContext *av, *av1;
3284
    int i;
3285

    
3286
    av = st->codec;
3287
    for(i=0;i<feed->nb_streams;i++) {
3288
        st = feed->streams[i];
3289
        av1 = st->codec;
3290
        if (av1->codec_id == av->codec_id &&
3291
            av1->codec_type == av->codec_type &&
3292
            av1->bit_rate == av->bit_rate) {
3293

    
3294
            switch(av->codec_type) {
3295
            case CODEC_TYPE_AUDIO:
3296
                if (av1->channels == av->channels &&
3297
                    av1->sample_rate == av->sample_rate)
3298
                    goto found;
3299
                break;
3300
            case CODEC_TYPE_VIDEO:
3301
                if (av1->width == av->width &&
3302
                    av1->height == av->height &&
3303
                    av1->time_base.den == av->time_base.den &&
3304
                    av1->time_base.num == av->time_base.num &&
3305
                    av1->gop_size == av->gop_size)
3306
                    goto found;
3307
                break;
3308
            default:
3309
                abort();
3310
            }
3311
        }
3312
    }
3313

    
3314
    fst = add_av_stream1(feed, av);
3315
    if (!fst)
3316
        return -1;
3317
    return feed->nb_streams - 1;
3318
 found:
3319
    return i;
3320
}
3321

    
3322
static void remove_stream(FFStream *stream)
3323
{
3324
    FFStream **ps;
3325
    ps = &first_stream;
3326
    while (*ps != NULL) {
3327
        if (*ps == stream) {
3328
            *ps = (*ps)->next;
3329
        } else {
3330
            ps = &(*ps)->next;
3331
        }
3332
    }
3333
}
3334

    
3335
/* specific mpeg4 handling : we extract the raw parameters */
3336
static void extract_mpeg4_header(AVFormatContext *infile)
3337
{
3338
    int mpeg4_count, i, size;
3339
    AVPacket pkt;
3340
    AVStream *st;
3341
    const uint8_t *p;
3342

    
3343
    mpeg4_count = 0;
3344
    for(i=0;i<infile->nb_streams;i++) {
3345
        st = infile->streams[i];
3346
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3347
            st->codec->extradata_size == 0) {
3348
            mpeg4_count++;
3349
        }
3350
    }
3351
    if (!mpeg4_count)
3352
        return;
3353

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

    
3384
/* compute the needed AVStream for each file */
3385
static void build_file_streams(void)
3386
{
3387
    FFStream *stream, *stream_next;
3388
    AVFormatContext *infile;
3389
    int i;
3390

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

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

    
3424
                for(i=0;i<infile->nb_streams;i++) {
3425
                    add_av_stream1(stream, infile->streams[i]->codec);
3426
                }
3427
                av_close_input_file(infile);
3428
            }
3429
        }
3430
    }
3431
}
3432

    
3433
/* compute the needed AVStream for each feed */
3434
static void build_feed_streams(void)
3435
{
3436
    FFStream *stream, *feed;
3437
    int i;
3438

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

    
3452
    /* gather all streams */
3453
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3454
        feed = stream->feed;
3455
        if (feed) {
3456
            if (stream->is_feed) {
3457
                for(i=0;i<stream->nb_streams;i++) {
3458
                    stream->feed_streams[i] = i;
3459
                }
3460
            }
3461
        }
3462
    }
3463

    
3464
    /* create feed files if needed */
3465
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3466
        int fd;
3467

    
3468
        if (url_exist(feed->feed_filename)) {
3469
            /* See if it matches */
3470
            AVFormatContext *s;
3471
            int matches = 0;
3472

    
3473
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3474
                /* Now see if it matches */
3475
                if (s->nb_streams == feed->nb_streams) {
3476
                    matches = 1;
3477
                    for(i=0;i<s->nb_streams;i++) {
3478
                        AVStream *sf, *ss;
3479
                        sf = feed->streams[i];
3480
                        ss = s->streams[i];
3481

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

    
3490
                            ccf = sf->codec;
3491
                            ccs = ss->codec;
3492
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3493

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

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

    
3546
            if (feed->readonly) {
3547
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3548
                    feed->feed_filename);
3549
                exit(1);
3550
            }
3551

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

    
3582
        feed->feed_write_index = ffm_read_write_index(fd);
3583
        feed->feed_size = lseek(fd, 0, SEEK_END);
3584
        /* ensure that we do not wrap before the end of file */
3585
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3586
            feed->feed_max_size = feed->feed_size;
3587

    
3588
        close(fd);
3589
    }
3590
}
3591

    
3592
/* compute the bandwidth used by each stream */
3593
static void compute_bandwidth(void)
3594
{
3595
    int bandwidth, i;
3596
    FFStream *stream;
3597

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

    
3615
static void get_arg(char *buf, int buf_size, const char **pp)
3616
{
3617
    const char *p;
3618
    char *q;
3619
    int quote;
3620

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

    
3647
/* add a codec and set the default parameters */
3648
static void add_codec(FFStream *stream, AVCodecContext *av)
3649
{
3650
    AVStream *st;
3651

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

    
3685
        if (!av->nsse_weight)
3686
            av->nsse_weight = 8;
3687

    
3688
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3689
        av->me_method = ME_EPZS;
3690
        av->rc_buffer_aggressivity = 1.0;
3691

    
3692
        if (!av->rc_eq)
3693
            av->rc_eq = "tex^qComp";
3694
        if (!av->i_quant_factor)
3695
            av->i_quant_factor = -0.8;
3696
        if (!av->b_quant_factor)
3697
            av->b_quant_factor = 1.25;
3698
        if (!av->b_quant_offset)
3699
            av->b_quant_offset = 1.25;
3700
        if (!av->rc_max_rate)
3701
            av->rc_max_rate = av->bit_rate * 2;
3702

    
3703
        if (av->rc_max_rate && !av->rc_buffer_size) {
3704
            av->rc_buffer_size = av->rc_max_rate;
3705
        }
3706

    
3707

    
3708
        break;
3709
    default:
3710
        abort();
3711
    }
3712

    
3713
    st = av_mallocz(sizeof(AVStream));
3714
    if (!st)
3715
        return;
3716
    st->codec = avcodec_alloc_context();
3717
    stream->streams[stream->nb_streams++] = st;
3718
    memcpy(st->codec, av, sizeof(AVCodecContext));
3719
}
3720

    
3721
static int opt_audio_codec(const char *arg)
3722
{
3723
    AVCodec *p;
3724

    
3725
    p = first_avcodec;
3726
    while (p) {
3727
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3728
            break;
3729
        p = p->next;
3730
    }
3731
    if (p == NULL) {
3732
        return CODEC_ID_NONE;
3733
    }
3734

    
3735
    return p->id;
3736
}
3737

    
3738
static int opt_video_codec(const char *arg)
3739
{
3740
    AVCodec *p;
3741

    
3742
    p = first_avcodec;
3743
    while (p) {
3744
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3745
            break;
3746
        p = p->next;
3747
    }
3748
    if (p == NULL) {
3749
        return CODEC_ID_NONE;
3750
    }
3751

    
3752
    return p->id;
3753
}
3754

    
3755
/* simplistic plugin support */
3756

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

    
3769
    init_func = dlsym(dll, "ffserver_module_init");
3770
    if (!init_func) {
3771
        fprintf(stderr,
3772
                "%s: init function 'ffserver_module_init()' not found\n",
3773
                filename);
3774
        dlclose(dll);
3775
    }
3776

    
3777
    init_func();
3778
}
3779
#endif
3780

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

    
3794
    f = fopen(filename, "r");
3795
    if (!f) {
3796
        perror(filename);
3797
        return -1;
3798
    }
3799

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

    
3821
        get_arg(cmd, sizeof(cmd), &p);
3822

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

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

    
3911
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3912

    
3913
                for (i = 0; i < 62; i++) {
3914
                    get_arg(arg, sizeof(arg), &p);
3915
                    if (!arg[0])
3916
                        break;
3917

    
3918
                    feed->child_argv[i] = av_strdup(arg);
3919
                }
3920

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

    
3923
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3924
                    "http://%s:%d/%s",
3925
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3926
                    inet_ntoa(my_http_addr.sin_addr),
3927
                    ntohs(my_http_addr.sin_port), feed->filename);
3928

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

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

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

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

    
4129
                get_arg(arg, sizeof(arg), &p);
4130

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

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

    
4291
            get_arg(arg, sizeof(arg), &p);
4292

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

    
4301
            get_arg(arg, sizeof(arg), &p);
4302

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

    
4311
            if (!errors) {
4312
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4313
                IPAddressACL **naclp = 0;
4314

    
4315
                acl.next = 0;
4316
                *nacl = acl;
4317

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

    
4328
                if (naclp) {
4329
                    while (*naclp)
4330
                        naclp = &(*naclp)->next;
4331

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

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

    
4435
    fclose(f);
4436
    if (errors)
4437
        return -1;
4438
    else
4439
        return 0;
4440
}
4441

    
4442
static void show_banner(void)
4443
{
4444
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4445
}
4446

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

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

    
4479
static void handle_child_exit(int sig)
4480
{
4481
    pid_t pid;
4482
    int status;
4483

    
4484
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4485
        FFStream *feed;
4486

    
4487
        for (feed = first_feed; feed; feed = feed->next) {
4488
            if (feed->pid == pid) {
4489
                int uptime = time(0) - feed->pid_start;
4490

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

    
4494
                if (uptime < 30) {
4495
                    /* Turn off any more restarts */
4496
                    feed->child_argv = 0;
4497
                }
4498
            }
4499
        }
4500
    }
4501

    
4502
    need_to_start_children = 1;
4503
}
4504

    
4505
int main(int argc, char **argv)
4506
{
4507
    const char *config_filename;
4508
    int c;
4509
    struct sigaction sigact;
4510

    
4511
    av_register_all();
4512

    
4513
    config_filename = "/etc/ffserver.conf";
4514

    
4515
    my_program_name = argv[0];
4516
    my_program_dir = getcwd(0, 0);
4517
    ffserver_daemon = 1;
4518

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

    
4546
    putenv("http_proxy");               /* Kill the http_proxy */
4547

    
4548
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4549

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

    
4555
    /* address on which the server will handle RTSP connections */
4556
    my_rtsp_addr.sin_family = AF_INET;
4557
    my_rtsp_addr.sin_port = htons (5454);
4558
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4559

    
4560
    nb_max_connections = 5;
4561
    max_bandwidth = 1000;
4562
    first_stream = NULL;
4563
    logfilename[0] = '\0';
4564

    
4565
    memset(&sigact, 0, sizeof(sigact));
4566
    sigact.sa_handler = handle_child_exit;
4567
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4568
    sigaction(SIGCHLD, &sigact, 0);
4569

    
4570
    if (parse_ffconfig(config_filename) < 0) {
4571
        fprintf(stderr, "Incorrect config file - exiting.\n");
4572
        exit(1);
4573
    }
4574

    
4575
    build_file_streams();
4576

    
4577
    build_feed_streams();
4578

    
4579
    compute_bandwidth();
4580

    
4581
    /* put the process in background and detach it from its TTY */
4582
    if (ffserver_daemon) {
4583
        int pid;
4584

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

    
4607
    /* signal init */
4608
    signal(SIGPIPE, SIG_IGN);
4609

    
4610
    /* open log file if needed */
4611
    if (logfilename[0] != '\0') {
4612
        if (!strcmp(logfilename, "-"))
4613
            logfile = stdout;
4614
        else
4615
            logfile = fopen(logfilename, "w");
4616
    }
4617

    
4618
    if (http_server() < 0) {
4619
        fprintf(stderr, "Could not start server\n");
4620
        exit(1);
4621
    }
4622

    
4623
    return 0;
4624
}