Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ e0c850a8

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 {
346
        if (cur_time - drd->time2 > 5000) {
347
            drd->time1 = drd->time2;
348
            drd->count1 = drd->count2;
349
            drd->time2 = cur_time;
350
            drd->count2 = count;
351
        }
352
    }
353
}
354

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

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

    
364

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

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

    
374
            feed->pid = fork();
375

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

    
386
                for (i = 3; i < 256; i++) {
387
                    close(i);
388
                }
389

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

    
400
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
401

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

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

    
413
                signal(SIGPIPE, SIG_DFL);
414

    
415
                execvp(pathname, feed->child_argv);
416

    
417
                _exit(1);
418
            }
419
        }
420
    }
421
}
422

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

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

    
434
    tmp = 1;
435
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
436

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

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

    
452
    return server_fd;
453
}
454

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

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

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

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

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

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

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

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

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

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

    
525
    http_log("ffserver started.\n");
526

    
527
    start_children(first_feed);
528

    
529
    first_http_ctx = NULL;
530
    nb_connections = 0;
531

    
532
    start_multicast();
533

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

    
540
        poll_entry->fd = rtsp_server_fd;
541
        poll_entry->events = POLLIN;
542
        poll_entry++;
543

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

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

    
603
        cur_time = av_gettime() / 1000;
604

    
605
        if (need_to_start_children) {
606
            need_to_start_children = 0;
607
            start_children(first_feed);
608
        }
609

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

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

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

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

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

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

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

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

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

    
679
    c->next = first_http_ctx;
680
    first_http_ctx = c;
681
    nb_connections++;
682

    
683
    start_wait_request(c, is_rtsp);
684

    
685
    return;
686

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

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

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

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

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

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

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

    
751
    ctx = &c->fmt_ctx;
752

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

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

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

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

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

    
782
static int handle_connection(HTTPContext *c)
783
{
784
    int len, ret;
785

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

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

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

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

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

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

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

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

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

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

    
968
            while (*q && *q != '\n' && isspace(*q))
969
                q++;
970

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

    
975
                q += 20;
976

    
977
                memset(rates, 0xff, ratelen);
978

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

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

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

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

    
1002
        p++;
1003
    }
1004

    
1005
    return 0;
1006
}
1007

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

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

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

    
1024
        /* Potential stream */
1025

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

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

    
1043
    return best;
1044
}
1045

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

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

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

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

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

    
1081
    return action_required;
1082
}
1083

    
1084

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1213
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1214

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

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

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

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

    
1240
        p++;
1241
    }
1242

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

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

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

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

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

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

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

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

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

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

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

    
1338
    if (redir_type != REDIR_NONE) {
1339
        char *hostinfo = 0;
1340

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

    
1350
            p++;
1351
        }
1352

    
1353
        if (hostinfo) {
1354
            char *eoh;
1355
            char hostbuf[260];
1356

    
1357
            while (isspace(*hostinfo))
1358
                hostinfo++;
1359

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

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

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

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

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

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

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

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

    
1458
    stream->conns_served++;
1459

    
1460
    /* XXX: add there authenticate and IP match */
1461

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

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

    
1483
                p++;
1484
            }
1485

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

    
1489
                logline += 17;
1490

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

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

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

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

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

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

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

    
1538
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1539
        goto send_stats;
1540

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

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

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

    
1559
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1560

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

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

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

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

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

    
1604
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1605
}
1606

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1771
                parameters[0] = 0;
1772

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

    
1791
        }
1792
        stream = stream->next;
1793
    }
1794

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1998

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2236
        c->last_packet_sent = 1;
2237
        break;
2238
    }
2239
    return 0;
2240
}
2241

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

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

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

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

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

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

    
2369
static int http_start_receive_data(HTTPContext *c)
2370
{
2371
    int fd;
2372

    
2373
    if (c->stream->feed_opened)
2374
        return -1;
2375

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

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

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

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

    
2397
static int http_receive_data(HTTPContext *c)
2398
{
2399
    HTTPContext *c1;
2400

    
2401
    if (c->buffer_end > c->buffer_ptr) {
2402
        int len;
2403

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

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

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

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

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

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

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

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

    
2466
            memset(&s, 0, sizeof(s));
2467

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

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

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

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

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

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

    
2510
/********************************************************************/
2511
/* RTSP handling */
2512

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

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

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

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

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

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

    
2589
    c->buffer_ptr[0] = '\0';
2590
    p = c->buffer;
2591

    
2592
    get_word(cmd, sizeof(cmd), &p);
2593
    get_word(url, sizeof(url), &p);
2594
    get_word(protocol, sizeof(protocol), &p);
2595

    
2596
    av_strlcpy(c->method, cmd, sizeof(c->method));
2597
    av_strlcpy(c->url, url, sizeof(c->url));
2598
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2599

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

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

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

    
2639
    /* handle sequence number */
2640
    c->seq = header->seq;
2641

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

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

    
2680
    if (url_open_dyn_buf(pb) < 0)
2681
        return -1;
2682

    
2683
    /* general media info */
2684

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

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

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

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

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

    
2795
 found:
2796
    /* prepare the media description in sdp format */
2797

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

    
2813
static HTTPContext *find_rtp_session(const char *session_id)
2814
{
2815
    HTTPContext *c;
2816

    
2817
    if (session_id[0] == '\0')
2818
        return NULL;
2819

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2976

    
2977
    url_fprintf(c->pb, "\r\n");
2978
}
2979

    
2980

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

    
2992
    rtp_c = find_rtp_session(session_id);
2993
    if (!rtp_c)
2994
        return NULL;
2995

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

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

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

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

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

    
3038
    rtp_c->state = HTTPSTATE_SEND_DATA;
3039

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

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

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

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

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

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

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

    
3083
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3084

    
3085
    /* abort the session */
3086
    close_connection(rtp_c);
3087

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

    
3095

    
3096
/********************************************************************/
3097
/* RTP handling */
3098

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

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

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

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

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

    
3148
    current_bandwidth += stream->bandwidth;
3149

    
3150
    c->next = first_http_ctx;
3151
    first_http_ctx = c;
3152
    return c;
3153

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

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

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

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

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

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

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

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

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

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

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

    
3257
    c->rtp_ctx[stream_index] = ctx;
3258
    return 0;
3259
}
3260

    
3261
/********************************************************************/
3262
/* ffserver initialization */
3263

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3590
        close(fd);
3591
    }
3592
}
3593

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

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

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

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

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

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

    
3687
        if (!av->nsse_weight)
3688
            av->nsse_weight = 8;
3689

    
3690
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3691
        av->me_method = ME_EPZS;
3692
        av->rc_buffer_aggressivity = 1.0;
3693

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

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

    
3709

    
3710
        break;
3711
    default:
3712
        abort();
3713
    }
3714

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

    
3723
static int opt_audio_codec(const char *arg)
3724
{
3725
    AVCodec *p;
3726

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

    
3737
    return p->id;
3738
}
3739

    
3740
static int opt_video_codec(const char *arg)
3741
{
3742
    AVCodec *p;
3743

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

    
3754
    return p->id;
3755
}
3756

    
3757
/* simplistic plugin support */
3758

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

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

    
3779
    init_func();
3780
}
3781
#endif
3782

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

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

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

    
3823
        get_arg(cmd, sizeof(cmd), &p);
3824

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

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

    
3913
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3914

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

    
3920
                    feed->child_argv[i] = av_strdup(arg);
3921
                }
3922

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

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

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

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

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

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

    
4131
                get_arg(arg, sizeof(arg), &p);
4132

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

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

    
4293
            get_arg(arg, sizeof(arg), &p);
4294

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

    
4303
            get_arg(arg, sizeof(arg), &p);
4304

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

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

    
4317
                acl.next = 0;
4318
                *nacl = acl;
4319

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

    
4330
                if (naclp) {
4331
                    while (*naclp)
4332
                        naclp = &(*naclp)->next;
4333

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

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

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

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

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

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

    
4481
static void handle_child_exit(int sig)
4482
{
4483
    pid_t pid;
4484
    int status;
4485

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

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

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

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

    
4504
    need_to_start_children = 1;
4505
}
4506

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

    
4513
    av_register_all();
4514

    
4515
    config_filename = "/etc/ffserver.conf";
4516

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

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

    
4548
    putenv("http_proxy");               /* Kill the http_proxy */
4549

    
4550
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4551

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

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

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

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

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

    
4577
    build_file_streams();
4578

    
4579
    build_feed_streams();
4580

    
4581
    compute_bandwidth();
4582

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

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

    
4609
    /* signal init */
4610
    signal(SIGPIPE, SIG_IGN);
4611

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

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

    
4625
    return 0;
4626
}