Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 72415b2a

History | View | Annotate | Download (153 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
#define _XOPEN_SOURCE 600
23

    
24
#include "config.h"
25
#if !HAVE_CLOSESOCKET
26
#define closesocket close
27
#endif
28
#include <string.h>
29
#include <strings.h>
30
#include <stdlib.h>
31
#include "libavformat/avformat.h"
32
#include "libavformat/network.h"
33
#include "libavformat/os_support.h"
34
#include "libavformat/rtpdec.h"
35
#include "libavformat/rtsp.h"
36
#include "libavutil/avstring.h"
37
#include "libavutil/lfg.h"
38
#include "libavutil/random_seed.h"
39
#include "libavcodec/opt.h"
40
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
44
#if HAVE_POLL_H
45
#include <poll.h>
46
#endif
47
#include <errno.h>
48
#include <sys/time.h>
49
#include <time.h>
50
#include <sys/wait.h>
51
#include <signal.h>
52
#if HAVE_DLFCN_H
53
#include <dlfcn.h>
54
#endif
55

    
56
#include "cmdutils.h"
57

    
58
const char program_name[] = "FFserver";
59
const int program_birth_year = 2000;
60

    
61
static const OptionDef options[];
62

    
63
enum HTTPState {
64
    HTTPSTATE_WAIT_REQUEST,
65
    HTTPSTATE_SEND_HEADER,
66
    HTTPSTATE_SEND_DATA_HEADER,
67
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
68
    HTTPSTATE_SEND_DATA_TRAILER,
69
    HTTPSTATE_RECEIVE_DATA,
70
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
71
    HTTPSTATE_READY,
72

    
73
    RTSPSTATE_WAIT_REQUEST,
74
    RTSPSTATE_SEND_REPLY,
75
    RTSPSTATE_SEND_PACKET,
76
};
77

    
78
static const char *http_state[] = {
79
    "HTTP_WAIT_REQUEST",
80
    "HTTP_SEND_HEADER",
81

    
82
    "SEND_DATA_HEADER",
83
    "SEND_DATA",
84
    "SEND_DATA_TRAILER",
85
    "RECEIVE_DATA",
86
    "WAIT_FEED",
87
    "READY",
88

    
89
    "RTSP_WAIT_REQUEST",
90
    "RTSP_SEND_REPLY",
91
    "RTSP_SEND_PACKET",
92
};
93

    
94
#define IOBUFFER_INIT_SIZE 8192
95

    
96
/* timeouts are in ms */
97
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
98
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
99

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

    
102
typedef struct RTSPActionServerSetup {
103
    uint32_t ipaddr;
104
    char transport_option[512];
105
} RTSPActionServerSetup;
106

    
107
typedef struct {
108
    int64_t count1, count2;
109
    int64_t time1, time2;
110
} DataRateData;
111

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

    
159
    /* RTSP state specific */
160
    uint8_t *pb_buffer; /* XXX: use that in all the code */
161
    ByteIOContext *pb;
162
    int seq; /* RTSP sequence number */
163

    
164
    /* RTP state specific */
165
    enum RTSPLowerTransport rtp_protocol;
166
    char session_id[32]; /* session id */
167
    AVFormatContext *rtp_ctx[MAX_STREAMS];
168

    
169
    /* RTP/UDP specific */
170
    URLContext *rtp_handles[MAX_STREAMS];
171

    
172
    /* RTP/TCP specific */
173
    struct HTTPContext *rtsp_c;
174
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
175
} HTTPContext;
176

    
177
/* each generated stream is described here */
178
enum StreamType {
179
    STREAM_TYPE_LIVE,
180
    STREAM_TYPE_STATUS,
181
    STREAM_TYPE_REDIRECT,
182
};
183

    
184
enum IPAddressAction {
185
    IP_ALLOW = 1,
186
    IP_DENY,
187
};
188

    
189
typedef struct IPAddressACL {
190
    struct IPAddressACL *next;
191
    enum IPAddressAction action;
192
    /* These are in host order */
193
    struct in_addr first;
194
    struct in_addr last;
195
} IPAddressACL;
196

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

    
233
    /* feed specific */
234
    int feed_opened;     /* true if someone is writing to the feed */
235
    int is_feed;         /* true if it is a feed */
236
    int readonly;        /* True if writing is prohibited to the file */
237
    int truncate;        /* True if feeder connection truncate the feed file */
238
    int conns_served;
239
    int64_t bytes_served;
240
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
241
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
242
    int64_t feed_size;          /* current size of feed */
243
    struct FFStream *next_feed;
244
} FFStream;
245

    
246
typedef struct FeedData {
247
    long long data_count;
248
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
249
} FeedData;
250

    
251
static struct sockaddr_in my_http_addr;
252
static struct sockaddr_in my_rtsp_addr;
253

    
254
static char logfilename[1024];
255
static HTTPContext *first_http_ctx;
256
static FFStream *first_feed;   /* contains only feeds */
257
static FFStream *first_stream; /* contains all streams, including feeds */
258

    
259
static void new_connection(int server_fd, int is_rtsp);
260
static void close_connection(HTTPContext *c);
261

    
262
/* HTTP handling */
263
static int handle_connection(HTTPContext *c);
264
static int http_parse_request(HTTPContext *c);
265
static int http_send_data(HTTPContext *c);
266
static void compute_status(HTTPContext *c);
267
static int open_input_stream(HTTPContext *c, const char *info);
268
static int http_start_receive_data(HTTPContext *c);
269
static int http_receive_data(HTTPContext *c);
270

    
271
/* RTSP handling */
272
static int rtsp_parse_request(HTTPContext *c);
273
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
274
static void rtsp_cmd_options(HTTPContext *c, const char *url);
275
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
276
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
277
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
278
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
279

    
280
/* SDP handling */
281
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
282
                                   struct in_addr my_ip);
283

    
284
/* RTP handling */
285
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
286
                                       FFStream *stream, const char *session_id,
287
                                       enum RTSPLowerTransport rtp_protocol);
288
static int rtp_new_av_stream(HTTPContext *c,
289
                             int stream_index, struct sockaddr_in *dest_addr,
290
                             HTTPContext *rtsp_c);
291

    
292
static const char *my_program_name;
293
static const char *my_program_dir;
294

    
295
static const char *config_filename;
296
static int ffserver_debug;
297
static int ffserver_daemon;
298
static int no_launch;
299
static int need_to_start_children;
300

    
301
/* maximum number of simultaneous HTTP connections */
302
static unsigned int nb_max_http_connections = 2000;
303
static unsigned int nb_max_connections = 5;
304
static unsigned int nb_connections;
305

    
306
static uint64_t max_bandwidth = 1000;
307
static uint64_t current_bandwidth;
308

    
309
static int64_t cur_time;           // Making this global saves on passing it around everywhere
310

    
311
static AVLFG random_state;
312

    
313
static FILE *logfile = NULL;
314

    
315
/* FIXME: make ffserver work with IPv6 */
316
/* resolve host with also IP address parsing */
317
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
318
{
319

    
320
    if (!ff_inet_aton(hostname, sin_addr)) {
321
#if HAVE_GETADDRINFO
322
        struct addrinfo *ai, *cur;
323
        struct addrinfo hints;
324
        memset(&hints, 0, sizeof(hints));
325
        hints.ai_family = AF_INET;
326
        if (getaddrinfo(hostname, NULL, &hints, &ai))
327
            return -1;
328
        /* getaddrinfo returns a linked list of addrinfo structs.
329
         * Even if we set ai_family = AF_INET above, make sure
330
         * that the returned one actually is of the correct type. */
331
        for (cur = ai; cur; cur = cur->ai_next) {
332
            if (cur->ai_family == AF_INET) {
333
                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
334
                freeaddrinfo(ai);
335
                return 0;
336
            }
337
        }
338
        freeaddrinfo(ai);
339
        return -1;
340
#else
341
        struct hostent *hp;
342
        hp = gethostbyname(hostname);
343
        if (!hp)
344
            return -1;
345
        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
346
#endif
347
    }
348
    return 0;
349
}
350

    
351
static char *ctime1(char *buf2)
352
{
353
    time_t ti;
354
    char *p;
355

    
356
    ti = time(NULL);
357
    p = ctime(&ti);
358
    strcpy(buf2, p);
359
    p = buf2 + strlen(p) - 1;
360
    if (*p == '\n')
361
        *p = '\0';
362
    return buf2;
363
}
364

    
365
static void http_vlog(const char *fmt, va_list vargs)
366
{
367
    static int print_prefix = 1;
368
    if (logfile) {
369
        if (print_prefix) {
370
            char buf[32];
371
            ctime1(buf);
372
            fprintf(logfile, "%s ", buf);
373
        }
374
        print_prefix = strstr(fmt, "\n") != NULL;
375
        vfprintf(logfile, fmt, vargs);
376
        fflush(logfile);
377
    }
378
}
379

    
380
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
381
{
382
    va_list vargs;
383
    va_start(vargs, fmt);
384
    http_vlog(fmt, vargs);
385
    va_end(vargs);
386
}
387

    
388
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
389
{
390
    static int print_prefix = 1;
391
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
392
    if (level > av_log_get_level())
393
        return;
394
    if (print_prefix && avc)
395
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
396
    print_prefix = strstr(fmt, "\n") != NULL;
397
    http_vlog(fmt, vargs);
398
}
399

    
400
static void log_connection(HTTPContext *c)
401
{
402
    if (c->suppress_log)
403
        return;
404

    
405
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
406
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
407
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
408
}
409

    
410
static void update_datarate(DataRateData *drd, int64_t count)
411
{
412
    if (!drd->time1 && !drd->count1) {
413
        drd->time1 = drd->time2 = cur_time;
414
        drd->count1 = drd->count2 = count;
415
    } else if (cur_time - drd->time2 > 5000) {
416
        drd->time1 = drd->time2;
417
        drd->count1 = drd->count2;
418
        drd->time2 = cur_time;
419
        drd->count2 = count;
420
    }
421
}
422

    
423
/* In bytes per second */
424
static int compute_datarate(DataRateData *drd, int64_t count)
425
{
426
    if (cur_time == drd->time1)
427
        return 0;
428

    
429
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
430
}
431

    
432

    
433
static void start_children(FFStream *feed)
434
{
435
    if (no_launch)
436
        return;
437

    
438
    for (; feed; feed = feed->next) {
439
        if (feed->child_argv && !feed->pid) {
440
            feed->pid_start = time(0);
441

    
442
            feed->pid = fork();
443

    
444
            if (feed->pid < 0) {
445
                http_log("Unable to create children\n");
446
                exit(1);
447
            }
448
            if (!feed->pid) {
449
                /* In child */
450
                char pathname[1024];
451
                char *slash;
452
                int i;
453

    
454
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
455

    
456
                slash = strrchr(pathname, '/');
457
                if (!slash)
458
                    slash = pathname;
459
                else
460
                    slash++;
461
                strcpy(slash, "ffmpeg");
462

    
463
                http_log("Launch commandline: ");
464
                http_log("%s ", pathname);
465
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
466
                    http_log("%s ", feed->child_argv[i]);
467
                http_log("\n");
468

    
469
                for (i = 3; i < 256; i++)
470
                    close(i);
471

    
472
                if (!ffserver_debug) {
473
                    i = open("/dev/null", O_RDWR);
474
                    if (i != -1) {
475
                        dup2(i, 0);
476
                        dup2(i, 1);
477
                        dup2(i, 2);
478
                        close(i);
479
                    }
480
                }
481

    
482
                /* This is needed to make relative pathnames work */
483
                chdir(my_program_dir);
484

    
485
                signal(SIGPIPE, SIG_DFL);
486

    
487
                execvp(pathname, feed->child_argv);
488

    
489
                _exit(1);
490
            }
491
        }
492
    }
493
}
494

    
495
/* open a listening socket */
496
static int socket_open_listen(struct sockaddr_in *my_addr)
497
{
498
    int server_fd, tmp;
499

    
500
    server_fd = socket(AF_INET,SOCK_STREAM,0);
501
    if (server_fd < 0) {
502
        perror ("socket");
503
        return -1;
504
    }
505

    
506
    tmp = 1;
507
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
508

    
509
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
510
        char bindmsg[32];
511
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
512
        perror (bindmsg);
513
        closesocket(server_fd);
514
        return -1;
515
    }
516

    
517
    if (listen (server_fd, 5) < 0) {
518
        perror ("listen");
519
        closesocket(server_fd);
520
        return -1;
521
    }
522
    ff_socket_nonblock(server_fd, 1);
523

    
524
    return server_fd;
525
}
526

    
527
/* start all multicast streams */
528
static void start_multicast(void)
529
{
530
    FFStream *stream;
531
    char session_id[32];
532
    HTTPContext *rtp_c;
533
    struct sockaddr_in dest_addr;
534
    int default_port, stream_index;
535

    
536
    default_port = 6000;
537
    for(stream = first_stream; stream != NULL; stream = stream->next) {
538
        if (stream->is_multicast) {
539
            /* open the RTP connection */
540
            snprintf(session_id, sizeof(session_id), "%08x%08x",
541
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
542

    
543
            /* choose a port if none given */
544
            if (stream->multicast_port == 0) {
545
                stream->multicast_port = default_port;
546
                default_port += 100;
547
            }
548

    
549
            dest_addr.sin_family = AF_INET;
550
            dest_addr.sin_addr = stream->multicast_ip;
551
            dest_addr.sin_port = htons(stream->multicast_port);
552

    
553
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
554
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
555
            if (!rtp_c)
556
                continue;
557

    
558
            if (open_input_stream(rtp_c, "") < 0) {
559
                http_log("Could not open input stream for stream '%s'\n",
560
                         stream->filename);
561
                continue;
562
            }
563

    
564
            /* open each RTP stream */
565
            for(stream_index = 0; stream_index < stream->nb_streams;
566
                stream_index++) {
567
                dest_addr.sin_port = htons(stream->multicast_port +
568
                                           2 * stream_index);
569
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
570
                    http_log("Could not open output stream '%s/streamid=%d'\n",
571
                             stream->filename, stream_index);
572
                    exit(1);
573
                }
574
            }
575

    
576
            /* change state to send data */
577
            rtp_c->state = HTTPSTATE_SEND_DATA;
578
        }
579
    }
580
}
581

    
582
/* main loop of the http server */
583
static int http_server(void)
584
{
585
    int server_fd = 0, rtsp_server_fd = 0;
586
    int ret, delay, delay1;
587
    struct pollfd *poll_table, *poll_entry;
588
    HTTPContext *c, *c_next;
589

    
590
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
591
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
592
        return -1;
593
    }
594

    
595
    if (my_http_addr.sin_port) {
596
        server_fd = socket_open_listen(&my_http_addr);
597
        if (server_fd < 0)
598
            return -1;
599
    }
600

    
601
    if (my_rtsp_addr.sin_port) {
602
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
603
        if (rtsp_server_fd < 0)
604
            return -1;
605
    }
606

    
607
    if (!rtsp_server_fd && !server_fd) {
608
        http_log("HTTP and RTSP disabled.\n");
609
        return -1;
610
    }
611

    
612
    http_log("FFserver started.\n");
613

    
614
    start_children(first_feed);
615

    
616
    start_multicast();
617

    
618
    for(;;) {
619
        poll_entry = poll_table;
620
        if (server_fd) {
621
            poll_entry->fd = server_fd;
622
            poll_entry->events = POLLIN;
623
            poll_entry++;
624
        }
625
        if (rtsp_server_fd) {
626
            poll_entry->fd = rtsp_server_fd;
627
            poll_entry->events = POLLIN;
628
            poll_entry++;
629
        }
630

    
631
        /* wait for events on each HTTP handle */
632
        c = first_http_ctx;
633
        delay = 1000;
634
        while (c != NULL) {
635
            int fd;
636
            fd = c->fd;
637
            switch(c->state) {
638
            case HTTPSTATE_SEND_HEADER:
639
            case RTSPSTATE_SEND_REPLY:
640
            case RTSPSTATE_SEND_PACKET:
641
                c->poll_entry = poll_entry;
642
                poll_entry->fd = fd;
643
                poll_entry->events = POLLOUT;
644
                poll_entry++;
645
                break;
646
            case HTTPSTATE_SEND_DATA_HEADER:
647
            case HTTPSTATE_SEND_DATA:
648
            case HTTPSTATE_SEND_DATA_TRAILER:
649
                if (!c->is_packetized) {
650
                    /* for TCP, we output as much as we can (may need to put a limit) */
651
                    c->poll_entry = poll_entry;
652
                    poll_entry->fd = fd;
653
                    poll_entry->events = POLLOUT;
654
                    poll_entry++;
655
                } else {
656
                    /* when ffserver is doing the timing, we work by
657
                       looking at which packet need to be sent every
658
                       10 ms */
659
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
660
                    if (delay1 < delay)
661
                        delay = delay1;
662
                }
663
                break;
664
            case HTTPSTATE_WAIT_REQUEST:
665
            case HTTPSTATE_RECEIVE_DATA:
666
            case HTTPSTATE_WAIT_FEED:
667
            case RTSPSTATE_WAIT_REQUEST:
668
                /* need to catch errors */
669
                c->poll_entry = poll_entry;
670
                poll_entry->fd = fd;
671
                poll_entry->events = POLLIN;/* Maybe this will work */
672
                poll_entry++;
673
                break;
674
            default:
675
                c->poll_entry = NULL;
676
                break;
677
            }
678
            c = c->next;
679
        }
680

    
681
        /* wait for an event on one connection. We poll at least every
682
           second to handle timeouts */
683
        do {
684
            ret = poll(poll_table, poll_entry - poll_table, delay);
685
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
686
                ff_neterrno() != FF_NETERROR(EINTR))
687
                return -1;
688
        } while (ret < 0);
689

    
690
        cur_time = av_gettime() / 1000;
691

    
692
        if (need_to_start_children) {
693
            need_to_start_children = 0;
694
            start_children(first_feed);
695
        }
696

    
697
        /* now handle the events */
698
        for(c = first_http_ctx; c != NULL; c = c_next) {
699
            c_next = c->next;
700
            if (handle_connection(c) < 0) {
701
                /* close and free the connection */
702
                log_connection(c);
703
                close_connection(c);
704
            }
705
        }
706

    
707
        poll_entry = poll_table;
708
        if (server_fd) {
709
            /* new HTTP connection request ? */
710
            if (poll_entry->revents & POLLIN)
711
                new_connection(server_fd, 0);
712
            poll_entry++;
713
        }
714
        if (rtsp_server_fd) {
715
            /* new RTSP connection request ? */
716
            if (poll_entry->revents & POLLIN)
717
                new_connection(rtsp_server_fd, 1);
718
        }
719
    }
720
}
721

    
722
/* start waiting for a new HTTP/RTSP request */
723
static void start_wait_request(HTTPContext *c, int is_rtsp)
724
{
725
    c->buffer_ptr = c->buffer;
726
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
727

    
728
    if (is_rtsp) {
729
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
730
        c->state = RTSPSTATE_WAIT_REQUEST;
731
    } else {
732
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
733
        c->state = HTTPSTATE_WAIT_REQUEST;
734
    }
735
}
736

    
737
static void http_send_too_busy_reply(int fd)
738
{
739
    char buffer[300];
740
    int len = snprintf(buffer, sizeof(buffer),
741
                       "HTTP/1.0 200 Server too busy\r\n"
742
                       "Content-type: text/html\r\n"
743
                       "\r\n"
744
                       "<html><head><title>Too busy</title></head><body>\r\n"
745
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
746
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
747
                       "</body></html>\r\n",
748
                       nb_connections, nb_max_connections);
749
    send(fd, buffer, len, 0);
750
}
751

    
752

    
753
static void new_connection(int server_fd, int is_rtsp)
754
{
755
    struct sockaddr_in from_addr;
756
    int fd, len;
757
    HTTPContext *c = NULL;
758

    
759
    len = sizeof(from_addr);
760
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
761
                &len);
762
    if (fd < 0) {
763
        http_log("error during accept %s\n", strerror(errno));
764
        return;
765
    }
766
    ff_socket_nonblock(fd, 1);
767

    
768
    if (nb_connections >= nb_max_connections) {
769
        http_send_too_busy_reply(fd);
770
        goto fail;
771
    }
772

    
773
    /* add a new connection */
774
    c = av_mallocz(sizeof(HTTPContext));
775
    if (!c)
776
        goto fail;
777

    
778
    c->fd = fd;
779
    c->poll_entry = NULL;
780
    c->from_addr = from_addr;
781
    c->buffer_size = IOBUFFER_INIT_SIZE;
782
    c->buffer = av_malloc(c->buffer_size);
783
    if (!c->buffer)
784
        goto fail;
785

    
786
    c->next = first_http_ctx;
787
    first_http_ctx = c;
788
    nb_connections++;
789

    
790
    start_wait_request(c, is_rtsp);
791

    
792
    return;
793

    
794
 fail:
795
    if (c) {
796
        av_free(c->buffer);
797
        av_free(c);
798
    }
799
    closesocket(fd);
800
}
801

    
802
static void close_connection(HTTPContext *c)
803
{
804
    HTTPContext **cp, *c1;
805
    int i, nb_streams;
806
    AVFormatContext *ctx;
807
    URLContext *h;
808
    AVStream *st;
809

    
810
    /* remove connection from list */
811
    cp = &first_http_ctx;
812
    while ((*cp) != NULL) {
813
        c1 = *cp;
814
        if (c1 == c)
815
            *cp = c->next;
816
        else
817
            cp = &c1->next;
818
    }
819

    
820
    /* remove references, if any (XXX: do it faster) */
821
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
822
        if (c1->rtsp_c == c)
823
            c1->rtsp_c = NULL;
824
    }
825

    
826
    /* remove connection associated resources */
827
    if (c->fd >= 0)
828
        closesocket(c->fd);
829
    if (c->fmt_in) {
830
        /* close each frame parser */
831
        for(i=0;i<c->fmt_in->nb_streams;i++) {
832
            st = c->fmt_in->streams[i];
833
            if (st->codec->codec)
834
                avcodec_close(st->codec);
835
        }
836
        av_close_input_file(c->fmt_in);
837
    }
838

    
839
    /* free RTP output streams if any */
840
    nb_streams = 0;
841
    if (c->stream)
842
        nb_streams = c->stream->nb_streams;
843

    
844
    for(i=0;i<nb_streams;i++) {
845
        ctx = c->rtp_ctx[i];
846
        if (ctx) {
847
            av_write_trailer(ctx);
848
            av_free(ctx);
849
        }
850
        h = c->rtp_handles[i];
851
        if (h)
852
            url_close(h);
853
    }
854

    
855
    ctx = &c->fmt_ctx;
856

    
857
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
858
        if (ctx->oformat) {
859
            /* prepare header */
860
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
861
                av_write_trailer(ctx);
862
                av_freep(&c->pb_buffer);
863
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
864
            }
865
        }
866
    }
867

    
868
    for(i=0; i<ctx->nb_streams; i++)
869
        av_free(ctx->streams[i]);
870

    
871
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
872
        current_bandwidth -= c->stream->bandwidth;
873

    
874
    /* signal that there is no feed if we are the feeder socket */
875
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
876
        c->stream->feed_opened = 0;
877
        close(c->feed_fd);
878
    }
879

    
880
    av_freep(&c->pb_buffer);
881
    av_freep(&c->packet_buffer);
882
    av_free(c->buffer);
883
    av_free(c);
884
    nb_connections--;
885
}
886

    
887
static int handle_connection(HTTPContext *c)
888
{
889
    int len, ret;
890

    
891
    switch(c->state) {
892
    case HTTPSTATE_WAIT_REQUEST:
893
    case RTSPSTATE_WAIT_REQUEST:
894
        /* timeout ? */
895
        if ((c->timeout - cur_time) < 0)
896
            return -1;
897
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
898
            return -1;
899

    
900
        /* no need to read if no events */
901
        if (!(c->poll_entry->revents & POLLIN))
902
            return 0;
903
        /* read the data */
904
    read_loop:
905
        len = recv(c->fd, c->buffer_ptr, 1, 0);
906
        if (len < 0) {
907
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
908
                ff_neterrno() != FF_NETERROR(EINTR))
909
                return -1;
910
        } else if (len == 0) {
911
            return -1;
912
        } else {
913
            /* search for end of request. */
914
            uint8_t *ptr;
915
            c->buffer_ptr += len;
916
            ptr = c->buffer_ptr;
917
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
918
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
919
                /* request found : parse it and reply */
920
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
921
                    ret = http_parse_request(c);
922
                } else {
923
                    ret = rtsp_parse_request(c);
924
                }
925
                if (ret < 0)
926
                    return -1;
927
            } else if (ptr >= c->buffer_end) {
928
                /* request too long: cannot do anything */
929
                return -1;
930
            } else goto read_loop;
931
        }
932
        break;
933

    
934
    case HTTPSTATE_SEND_HEADER:
935
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
936
            return -1;
937

    
938
        /* no need to write if no events */
939
        if (!(c->poll_entry->revents & POLLOUT))
940
            return 0;
941
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
942
        if (len < 0) {
943
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
944
                ff_neterrno() != FF_NETERROR(EINTR)) {
945
                /* error : close connection */
946
                av_freep(&c->pb_buffer);
947
                return -1;
948
            }
949
        } else {
950
            c->buffer_ptr += len;
951
            if (c->stream)
952
                c->stream->bytes_served += len;
953
            c->data_count += len;
954
            if (c->buffer_ptr >= c->buffer_end) {
955
                av_freep(&c->pb_buffer);
956
                /* if error, exit */
957
                if (c->http_error)
958
                    return -1;
959
                /* all the buffer was sent : synchronize to the incoming stream */
960
                c->state = HTTPSTATE_SEND_DATA_HEADER;
961
                c->buffer_ptr = c->buffer_end = c->buffer;
962
            }
963
        }
964
        break;
965

    
966
    case HTTPSTATE_SEND_DATA:
967
    case HTTPSTATE_SEND_DATA_HEADER:
968
    case HTTPSTATE_SEND_DATA_TRAILER:
969
        /* for packetized output, we consider we can always write (the
970
           input streams sets the speed). It may be better to verify
971
           that we do not rely too much on the kernel queues */
972
        if (!c->is_packetized) {
973
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
974
                return -1;
975

    
976
            /* no need to read if no events */
977
            if (!(c->poll_entry->revents & POLLOUT))
978
                return 0;
979
        }
980
        if (http_send_data(c) < 0)
981
            return -1;
982
        /* close connection if trailer sent */
983
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
984
            return -1;
985
        break;
986
    case HTTPSTATE_RECEIVE_DATA:
987
        /* no need to read if no events */
988
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
989
            return -1;
990
        if (!(c->poll_entry->revents & POLLIN))
991
            return 0;
992
        if (http_receive_data(c) < 0)
993
            return -1;
994
        break;
995
    case HTTPSTATE_WAIT_FEED:
996
        /* no need to read if no events */
997
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
998
            return -1;
999

    
1000
        /* nothing to do, we'll be waken up by incoming feed packets */
1001
        break;
1002

    
1003
    case RTSPSTATE_SEND_REPLY:
1004
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1005
            av_freep(&c->pb_buffer);
1006
            return -1;
1007
        }
1008
        /* no need to write if no events */
1009
        if (!(c->poll_entry->revents & POLLOUT))
1010
            return 0;
1011
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1012
        if (len < 0) {
1013
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1014
                ff_neterrno() != FF_NETERROR(EINTR)) {
1015
                /* error : close connection */
1016
                av_freep(&c->pb_buffer);
1017
                return -1;
1018
            }
1019
        } else {
1020
            c->buffer_ptr += len;
1021
            c->data_count += len;
1022
            if (c->buffer_ptr >= c->buffer_end) {
1023
                /* all the buffer was sent : wait for a new request */
1024
                av_freep(&c->pb_buffer);
1025
                start_wait_request(c, 1);
1026
            }
1027
        }
1028
        break;
1029
    case RTSPSTATE_SEND_PACKET:
1030
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1031
            av_freep(&c->packet_buffer);
1032
            return -1;
1033
        }
1034
        /* no need to write if no events */
1035
        if (!(c->poll_entry->revents & POLLOUT))
1036
            return 0;
1037
        len = send(c->fd, c->packet_buffer_ptr,
1038
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1039
        if (len < 0) {
1040
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1041
                ff_neterrno() != FF_NETERROR(EINTR)) {
1042
                /* error : close connection */
1043
                av_freep(&c->packet_buffer);
1044
                return -1;
1045
            }
1046
        } else {
1047
            c->packet_buffer_ptr += len;
1048
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1049
                /* all the buffer was sent : wait for a new request */
1050
                av_freep(&c->packet_buffer);
1051
                c->state = RTSPSTATE_WAIT_REQUEST;
1052
            }
1053
        }
1054
        break;
1055
    case HTTPSTATE_READY:
1056
        /* nothing to do */
1057
        break;
1058
    default:
1059
        return -1;
1060
    }
1061
    return 0;
1062
}
1063

    
1064
static int extract_rates(char *rates, int ratelen, const char *request)
1065
{
1066
    const char *p;
1067

    
1068
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1069
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1070
            const char *q = p + 7;
1071

    
1072
            while (*q && *q != '\n' && isspace(*q))
1073
                q++;
1074

    
1075
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1076
                int stream_no;
1077
                int rate_no;
1078

    
1079
                q += 20;
1080

    
1081
                memset(rates, 0xff, ratelen);
1082

    
1083
                while (1) {
1084
                    while (*q && *q != '\n' && *q != ':')
1085
                        q++;
1086

    
1087
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1088
                        break;
1089

    
1090
                    stream_no--;
1091
                    if (stream_no < ratelen && stream_no >= 0)
1092
                        rates[stream_no] = rate_no;
1093

    
1094
                    while (*q && *q != '\n' && !isspace(*q))
1095
                        q++;
1096
                }
1097

    
1098
                return 1;
1099
            }
1100
        }
1101
        p = strchr(p, '\n');
1102
        if (!p)
1103
            break;
1104

    
1105
        p++;
1106
    }
1107

    
1108
    return 0;
1109
}
1110

    
1111
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1112
{
1113
    int i;
1114
    int best_bitrate = 100000000;
1115
    int best = -1;
1116

    
1117
    for (i = 0; i < feed->nb_streams; i++) {
1118
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1119

    
1120
        if (feed_codec->codec_id != codec->codec_id ||
1121
            feed_codec->sample_rate != codec->sample_rate ||
1122
            feed_codec->width != codec->width ||
1123
            feed_codec->height != codec->height)
1124
            continue;
1125

    
1126
        /* Potential stream */
1127

    
1128
        /* We want the fastest stream less than bit_rate, or the slowest
1129
         * faster than bit_rate
1130
         */
1131

    
1132
        if (feed_codec->bit_rate <= bit_rate) {
1133
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1134
                best_bitrate = feed_codec->bit_rate;
1135
                best = i;
1136
            }
1137
        } else {
1138
            if (feed_codec->bit_rate < best_bitrate) {
1139
                best_bitrate = feed_codec->bit_rate;
1140
                best = i;
1141
            }
1142
        }
1143
    }
1144

    
1145
    return best;
1146
}
1147

    
1148
static int modify_current_stream(HTTPContext *c, char *rates)
1149
{
1150
    int i;
1151
    FFStream *req = c->stream;
1152
    int action_required = 0;
1153

    
1154
    /* Not much we can do for a feed */
1155
    if (!req->feed)
1156
        return 0;
1157

    
1158
    for (i = 0; i < req->nb_streams; i++) {
1159
        AVCodecContext *codec = req->streams[i]->codec;
1160

    
1161
        switch(rates[i]) {
1162
            case 0:
1163
                c->switch_feed_streams[i] = req->feed_streams[i];
1164
                break;
1165
            case 1:
1166
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1167
                break;
1168
            case 2:
1169
                /* Wants off or slow */
1170
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1171
#ifdef WANTS_OFF
1172
                /* This doesn't work well when it turns off the only stream! */
1173
                c->switch_feed_streams[i] = -2;
1174
                c->feed_streams[i] = -2;
1175
#endif
1176
                break;
1177
        }
1178

    
1179
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1180
            action_required = 1;
1181
    }
1182

    
1183
    return action_required;
1184
}
1185

    
1186

    
1187
static void do_switch_stream(HTTPContext *c, int i)
1188
{
1189
    if (c->switch_feed_streams[i] >= 0) {
1190
#ifdef PHILIP
1191
        c->feed_streams[i] = c->switch_feed_streams[i];
1192
#endif
1193

    
1194
        /* Now update the stream */
1195
    }
1196
    c->switch_feed_streams[i] = -1;
1197
}
1198

    
1199
/* XXX: factorize in utils.c ? */
1200
/* XXX: take care with different space meaning */
1201
static void skip_spaces(const char **pp)
1202
{
1203
    const char *p;
1204
    p = *pp;
1205
    while (*p == ' ' || *p == '\t')
1206
        p++;
1207
    *pp = p;
1208
}
1209

    
1210
static void get_word(char *buf, int buf_size, const char **pp)
1211
{
1212
    const char *p;
1213
    char *q;
1214

    
1215
    p = *pp;
1216
    skip_spaces(&p);
1217
    q = buf;
1218
    while (!isspace(*p) && *p != '\0') {
1219
        if ((q - buf) < buf_size - 1)
1220
            *q++ = *p;
1221
        p++;
1222
    }
1223
    if (buf_size > 0)
1224
        *q = '\0';
1225
    *pp = p;
1226
}
1227

    
1228
static void get_arg(char *buf, int buf_size, const char **pp)
1229
{
1230
    const char *p;
1231
    char *q;
1232
    int quote;
1233

    
1234
    p = *pp;
1235
    while (isspace(*p)) p++;
1236
    q = buf;
1237
    quote = 0;
1238
    if (*p == '\"' || *p == '\'')
1239
        quote = *p++;
1240
    for(;;) {
1241
        if (quote) {
1242
            if (*p == quote)
1243
                break;
1244
        } else {
1245
            if (isspace(*p))
1246
                break;
1247
        }
1248
        if (*p == '\0')
1249
            break;
1250
        if ((q - buf) < buf_size - 1)
1251
            *q++ = *p;
1252
        p++;
1253
    }
1254
    *q = '\0';
1255
    if (quote && *p == quote)
1256
        p++;
1257
    *pp = p;
1258
}
1259

    
1260
static int validate_acl(FFStream *stream, HTTPContext *c)
1261
{
1262
    enum IPAddressAction last_action = IP_DENY;
1263
    IPAddressACL *acl;
1264
    struct in_addr *src = &c->from_addr.sin_addr;
1265
    unsigned long src_addr = src->s_addr;
1266

    
1267
    for (acl = stream->acl; acl; acl = acl->next) {
1268
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1269
            return (acl->action == IP_ALLOW) ? 1 : 0;
1270
        last_action = acl->action;
1271
    }
1272

    
1273
    /* Nothing matched, so return not the last action */
1274
    return (last_action == IP_DENY) ? 1 : 0;
1275
}
1276

    
1277
/* compute the real filename of a file by matching it without its
1278
   extensions to all the stream filenames */
1279
static void compute_real_filename(char *filename, int max_size)
1280
{
1281
    char file1[1024];
1282
    char file2[1024];
1283
    char *p;
1284
    FFStream *stream;
1285

    
1286
    /* compute filename by matching without the file extensions */
1287
    av_strlcpy(file1, filename, sizeof(file1));
1288
    p = strrchr(file1, '.');
1289
    if (p)
1290
        *p = '\0';
1291
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1292
        av_strlcpy(file2, stream->filename, sizeof(file2));
1293
        p = strrchr(file2, '.');
1294
        if (p)
1295
            *p = '\0';
1296
        if (!strcmp(file1, file2)) {
1297
            av_strlcpy(filename, stream->filename, max_size);
1298
            break;
1299
        }
1300
    }
1301
}
1302

    
1303
enum RedirType {
1304
    REDIR_NONE,
1305
    REDIR_ASX,
1306
    REDIR_RAM,
1307
    REDIR_ASF,
1308
    REDIR_RTSP,
1309
    REDIR_SDP,
1310
};
1311

    
1312
/* parse http request and prepare header */
1313
static int http_parse_request(HTTPContext *c)
1314
{
1315
    char *p;
1316
    enum RedirType redir_type;
1317
    char cmd[32];
1318
    char info[1024], filename[1024];
1319
    char url[1024], *q;
1320
    char protocol[32];
1321
    char msg[1024];
1322
    const char *mime_type;
1323
    FFStream *stream;
1324
    int i;
1325
    char ratebuf[32];
1326
    char *useragent = 0;
1327

    
1328
    p = c->buffer;
1329
    get_word(cmd, sizeof(cmd), (const char **)&p);
1330
    av_strlcpy(c->method, cmd, sizeof(c->method));
1331

    
1332
    if (!strcmp(cmd, "GET"))
1333
        c->post = 0;
1334
    else if (!strcmp(cmd, "POST"))
1335
        c->post = 1;
1336
    else
1337
        return -1;
1338

    
1339
    get_word(url, sizeof(url), (const char **)&p);
1340
    av_strlcpy(c->url, url, sizeof(c->url));
1341

    
1342
    get_word(protocol, sizeof(protocol), (const char **)&p);
1343
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1344
        return -1;
1345

    
1346
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1347

    
1348
    if (ffserver_debug)
1349
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1350

    
1351
    /* find the filename and the optional info string in the request */
1352
    p = strchr(url, '?');
1353
    if (p) {
1354
        av_strlcpy(info, p, sizeof(info));
1355
        *p = '\0';
1356
    } else
1357
        info[0] = '\0';
1358

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

    
1361
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1362
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1363
            useragent = p + 11;
1364
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1365
                useragent++;
1366
            break;
1367
        }
1368
        p = strchr(p, '\n');
1369
        if (!p)
1370
            break;
1371

    
1372
        p++;
1373
    }
1374

    
1375
    redir_type = REDIR_NONE;
1376
    if (av_match_ext(filename, "asx")) {
1377
        redir_type = REDIR_ASX;
1378
        filename[strlen(filename)-1] = 'f';
1379
    } else if (av_match_ext(filename, "asf") &&
1380
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1381
        /* if this isn't WMP or lookalike, return the redirector file */
1382
        redir_type = REDIR_ASF;
1383
    } else if (av_match_ext(filename, "rpm,ram")) {
1384
        redir_type = REDIR_RAM;
1385
        strcpy(filename + strlen(filename)-2, "m");
1386
    } else if (av_match_ext(filename, "rtsp")) {
1387
        redir_type = REDIR_RTSP;
1388
        compute_real_filename(filename, sizeof(filename) - 1);
1389
    } else if (av_match_ext(filename, "sdp")) {
1390
        redir_type = REDIR_SDP;
1391
        compute_real_filename(filename, sizeof(filename) - 1);
1392
    }
1393

    
1394
    // "redirect" / request to index.html
1395
    if (!strlen(filename))
1396
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1397

    
1398
    stream = first_stream;
1399
    while (stream != NULL) {
1400
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1401
            break;
1402
        stream = stream->next;
1403
    }
1404
    if (stream == NULL) {
1405
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1406
        http_log("File '%s' not found\n", url);
1407
        goto send_error;
1408
    }
1409

    
1410
    c->stream = stream;
1411
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1412
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1413

    
1414
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1415
        c->http_error = 301;
1416
        q = c->buffer;
1417
        q += snprintf(q, c->buffer_size,
1418
                      "HTTP/1.0 301 Moved\r\n"
1419
                      "Location: %s\r\n"
1420
                      "Content-type: text/html\r\n"
1421
                      "\r\n"
1422
                      "<html><head><title>Moved</title></head><body>\r\n"
1423
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1424
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1425
        /* prepare output buffer */
1426
        c->buffer_ptr = c->buffer;
1427
        c->buffer_end = q;
1428
        c->state = HTTPSTATE_SEND_HEADER;
1429
        return 0;
1430
    }
1431

    
1432
    /* If this is WMP, get the rate information */
1433
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1434
        if (modify_current_stream(c, ratebuf)) {
1435
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1436
                if (c->switch_feed_streams[i] >= 0)
1437
                    do_switch_stream(c, i);
1438
            }
1439
        }
1440
    }
1441

    
1442
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1443
        current_bandwidth += stream->bandwidth;
1444

    
1445
    /* If already streaming this feed, do not let start another feeder. */
1446
    if (stream->feed_opened) {
1447
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1448
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1449
        goto send_error;
1450
    }
1451

    
1452
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1453
        c->http_error = 200;
1454
        q = c->buffer;
1455
        q += snprintf(q, c->buffer_size,
1456
                      "HTTP/1.0 200 Server too busy\r\n"
1457
                      "Content-type: text/html\r\n"
1458
                      "\r\n"
1459
                      "<html><head><title>Too busy</title></head><body>\r\n"
1460
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1461
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1462
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1463
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1464
        /* prepare output buffer */
1465
        c->buffer_ptr = c->buffer;
1466
        c->buffer_end = q;
1467
        c->state = HTTPSTATE_SEND_HEADER;
1468
        return 0;
1469
    }
1470

    
1471
    if (redir_type != REDIR_NONE) {
1472
        char *hostinfo = 0;
1473

    
1474
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1475
            if (strncasecmp(p, "Host:", 5) == 0) {
1476
                hostinfo = p + 5;
1477
                break;
1478
            }
1479
            p = strchr(p, '\n');
1480
            if (!p)
1481
                break;
1482

    
1483
            p++;
1484
        }
1485

    
1486
        if (hostinfo) {
1487
            char *eoh;
1488
            char hostbuf[260];
1489

    
1490
            while (isspace(*hostinfo))
1491
                hostinfo++;
1492

    
1493
            eoh = strchr(hostinfo, '\n');
1494
            if (eoh) {
1495
                if (eoh[-1] == '\r')
1496
                    eoh--;
1497

    
1498
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1499
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1500
                    hostbuf[eoh - hostinfo] = 0;
1501

    
1502
                    c->http_error = 200;
1503
                    q = c->buffer;
1504
                    switch(redir_type) {
1505
                    case REDIR_ASX:
1506
                        q += snprintf(q, c->buffer_size,
1507
                                      "HTTP/1.0 200 ASX Follows\r\n"
1508
                                      "Content-type: video/x-ms-asf\r\n"
1509
                                      "\r\n"
1510
                                      "<ASX Version=\"3\">\r\n"
1511
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1512
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1513
                                      "</ASX>\r\n", hostbuf, filename, info);
1514
                        break;
1515
                    case REDIR_RAM:
1516
                        q += snprintf(q, c->buffer_size,
1517
                                      "HTTP/1.0 200 RAM Follows\r\n"
1518
                                      "Content-type: audio/x-pn-realaudio\r\n"
1519
                                      "\r\n"
1520
                                      "# Autogenerated by ffserver\r\n"
1521
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1522
                        break;
1523
                    case REDIR_ASF:
1524
                        q += snprintf(q, c->buffer_size,
1525
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1526
                                      "Content-type: video/x-ms-asf\r\n"
1527
                                      "\r\n"
1528
                                      "[Reference]\r\n"
1529
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1530
                        break;
1531
                    case REDIR_RTSP:
1532
                        {
1533
                            char hostname[256], *p;
1534
                            /* extract only hostname */
1535
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1536
                            p = strrchr(hostname, ':');
1537
                            if (p)
1538
                                *p = '\0';
1539
                            q += snprintf(q, c->buffer_size,
1540
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1541
                                          /* XXX: incorrect mime type ? */
1542
                                          "Content-type: application/x-rtsp\r\n"
1543
                                          "\r\n"
1544
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1545
                        }
1546
                        break;
1547
                    case REDIR_SDP:
1548
                        {
1549
                            uint8_t *sdp_data;
1550
                            int sdp_data_size, len;
1551
                            struct sockaddr_in my_addr;
1552

    
1553
                            q += snprintf(q, c->buffer_size,
1554
                                          "HTTP/1.0 200 OK\r\n"
1555
                                          "Content-type: application/sdp\r\n"
1556
                                          "\r\n");
1557

    
1558
                            len = sizeof(my_addr);
1559
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1560

    
1561
                            /* XXX: should use a dynamic buffer */
1562
                            sdp_data_size = prepare_sdp_description(stream,
1563
                                                                    &sdp_data,
1564
                                                                    my_addr.sin_addr);
1565
                            if (sdp_data_size > 0) {
1566
                                memcpy(q, sdp_data, sdp_data_size);
1567
                                q += sdp_data_size;
1568
                                *q = '\0';
1569
                                av_free(sdp_data);
1570
                            }
1571
                        }
1572
                        break;
1573
                    default:
1574
                        abort();
1575
                        break;
1576
                    }
1577

    
1578
                    /* prepare output buffer */
1579
                    c->buffer_ptr = c->buffer;
1580
                    c->buffer_end = q;
1581
                    c->state = HTTPSTATE_SEND_HEADER;
1582
                    return 0;
1583
                }
1584
            }
1585
        }
1586

    
1587
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1588
        goto send_error;
1589
    }
1590

    
1591
    stream->conns_served++;
1592

    
1593
    /* XXX: add there authenticate and IP match */
1594

    
1595
    if (c->post) {
1596
        /* if post, it means a feed is being sent */
1597
        if (!stream->is_feed) {
1598
            /* However it might be a status report from WMP! Let us log the
1599
             * data as it might come in handy one day. */
1600
            char *logline = 0;
1601
            int client_id = 0;
1602

    
1603
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1604
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1605
                    logline = p;
1606
                    break;
1607
                }
1608
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1609
                    client_id = strtol(p + 18, 0, 10);
1610
                p = strchr(p, '\n');
1611
                if (!p)
1612
                    break;
1613

    
1614
                p++;
1615
            }
1616

    
1617
            if (logline) {
1618
                char *eol = strchr(logline, '\n');
1619

    
1620
                logline += 17;
1621

    
1622
                if (eol) {
1623
                    if (eol[-1] == '\r')
1624
                        eol--;
1625
                    http_log("%.*s\n", (int) (eol - logline), logline);
1626
                    c->suppress_log = 1;
1627
                }
1628
            }
1629

    
1630
#ifdef DEBUG_WMP
1631
            http_log("\nGot request:\n%s\n", c->buffer);
1632
#endif
1633

    
1634
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1635
                HTTPContext *wmpc;
1636

    
1637
                /* Now we have to find the client_id */
1638
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1639
                    if (wmpc->wmp_client_id == client_id)
1640
                        break;
1641
                }
1642

    
1643
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1644
                    wmpc->switch_pending = 1;
1645
            }
1646

    
1647
            snprintf(msg, sizeof(msg), "POST command not handled");
1648
            c->stream = 0;
1649
            goto send_error;
1650
        }
1651
        if (http_start_receive_data(c) < 0) {
1652
            snprintf(msg, sizeof(msg), "could not open feed");
1653
            goto send_error;
1654
        }
1655
        c->http_error = 0;
1656
        c->state = HTTPSTATE_RECEIVE_DATA;
1657
        return 0;
1658
    }
1659

    
1660
#ifdef DEBUG_WMP
1661
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1662
        http_log("\nGot request:\n%s\n", c->buffer);
1663
#endif
1664

    
1665
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1666
        goto send_status;
1667

    
1668
    /* open input stream */
1669
    if (open_input_stream(c, info) < 0) {
1670
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1671
        goto send_error;
1672
    }
1673

    
1674
    /* prepare http header */
1675
    q = c->buffer;
1676
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1677
    mime_type = c->stream->fmt->mime_type;
1678
    if (!mime_type)
1679
        mime_type = "application/x-octet-stream";
1680
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1681

    
1682
    /* for asf, we need extra headers */
1683
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1684
        /* Need to allocate a client id */
1685

    
1686
        c->wmp_client_id = av_lfg_get(&random_state);
1687

    
1688
        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);
1689
    }
1690
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1691
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1692

    
1693
    /* prepare output buffer */
1694
    c->http_error = 0;
1695
    c->buffer_ptr = c->buffer;
1696
    c->buffer_end = q;
1697
    c->state = HTTPSTATE_SEND_HEADER;
1698
    return 0;
1699
 send_error:
1700
    c->http_error = 404;
1701
    q = c->buffer;
1702
    q += snprintf(q, c->buffer_size,
1703
                  "HTTP/1.0 404 Not Found\r\n"
1704
                  "Content-type: text/html\r\n"
1705
                  "\r\n"
1706
                  "<html>\n"
1707
                  "<head><title>404 Not Found</title></head>\n"
1708
                  "<body>%s</body>\n"
1709
                  "</html>\n", msg);
1710
    /* prepare output buffer */
1711
    c->buffer_ptr = c->buffer;
1712
    c->buffer_end = q;
1713
    c->state = HTTPSTATE_SEND_HEADER;
1714
    return 0;
1715
 send_status:
1716
    compute_status(c);
1717
    c->http_error = 200; /* horrible : we use this value to avoid
1718
                            going to the send data state */
1719
    c->state = HTTPSTATE_SEND_HEADER;
1720
    return 0;
1721
}
1722

    
1723
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1724
{
1725
    static const char *suffix = " kMGTP";
1726
    const char *s;
1727

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

    
1730
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1731
}
1732

    
1733
static void compute_status(HTTPContext *c)
1734
{
1735
    HTTPContext *c1;
1736
    FFStream *stream;
1737
    char *p;
1738
    time_t ti;
1739
    int i, len;
1740
    ByteIOContext *pb;
1741

    
1742
    if (url_open_dyn_buf(&pb) < 0) {
1743
        /* XXX: return an error ? */
1744
        c->buffer_ptr = c->buffer;
1745
        c->buffer_end = c->buffer;
1746
        return;
1747
    }
1748

    
1749
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1750
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1751
    url_fprintf(pb, "Pragma: no-cache\r\n");
1752
    url_fprintf(pb, "\r\n");
1753

    
1754
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1755
    if (c->stream->feed_filename[0])
1756
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1757
    url_fprintf(pb, "</head>\n<body>");
1758
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1759
    /* format status */
1760
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1761
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1762
    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");
1763
    stream = first_stream;
1764
    while (stream != NULL) {
1765
        char sfilename[1024];
1766
        char *eosf;
1767

    
1768
        if (stream->feed != stream) {
1769
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1770
            eosf = sfilename + strlen(sfilename);
1771
            if (eosf - sfilename >= 4) {
1772
                if (strcmp(eosf - 4, ".asf") == 0)
1773
                    strcpy(eosf - 4, ".asx");
1774
                else if (strcmp(eosf - 3, ".rm") == 0)
1775
                    strcpy(eosf - 3, ".ram");
1776
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1777
                    /* generate a sample RTSP director if
1778
                       unicast. Generate an SDP redirector if
1779
                       multicast */
1780
                    eosf = strrchr(sfilename, '.');
1781
                    if (!eosf)
1782
                        eosf = sfilename + strlen(sfilename);
1783
                    if (stream->is_multicast)
1784
                        strcpy(eosf, ".sdp");
1785
                    else
1786
                        strcpy(eosf, ".rtsp");
1787
                }
1788
            }
1789

    
1790
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1791
                         sfilename, stream->filename);
1792
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1793
                        stream->conns_served);
1794
            fmt_bytecount(pb, stream->bytes_served);
1795
            switch(stream->stream_type) {
1796
            case STREAM_TYPE_LIVE: {
1797
                    int audio_bit_rate = 0;
1798
                    int video_bit_rate = 0;
1799
                    const char *audio_codec_name = "";
1800
                    const char *video_codec_name = "";
1801
                    const char *audio_codec_name_extra = "";
1802
                    const char *video_codec_name_extra = "";
1803

    
1804
                    for(i=0;i<stream->nb_streams;i++) {
1805
                        AVStream *st = stream->streams[i];
1806
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1807
                        switch(st->codec->codec_type) {
1808
                        case AVMEDIA_TYPE_AUDIO:
1809
                            audio_bit_rate += st->codec->bit_rate;
1810
                            if (codec) {
1811
                                if (*audio_codec_name)
1812
                                    audio_codec_name_extra = "...";
1813
                                audio_codec_name = codec->name;
1814
                            }
1815
                            break;
1816
                        case AVMEDIA_TYPE_VIDEO:
1817
                            video_bit_rate += st->codec->bit_rate;
1818
                            if (codec) {
1819
                                if (*video_codec_name)
1820
                                    video_codec_name_extra = "...";
1821
                                video_codec_name = codec->name;
1822
                            }
1823
                            break;
1824
                        case AVMEDIA_TYPE_DATA:
1825
                            video_bit_rate += st->codec->bit_rate;
1826
                            break;
1827
                        default:
1828
                            abort();
1829
                        }
1830
                    }
1831
                    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",
1832
                                 stream->fmt->name,
1833
                                 stream->bandwidth,
1834
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1835
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1836
                    if (stream->feed)
1837
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1838
                    else
1839
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1840
                    url_fprintf(pb, "\n");
1841
                }
1842
                break;
1843
            default:
1844
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1845
                break;
1846
            }
1847
        }
1848
        stream = stream->next;
1849
    }
1850
    url_fprintf(pb, "</table>\n");
1851

    
1852
    stream = first_stream;
1853
    while (stream != NULL) {
1854
        if (stream->feed == stream) {
1855
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1856
            if (stream->pid) {
1857
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1858

    
1859
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1860
                {
1861
                    FILE *pid_stat;
1862
                    char ps_cmd[64];
1863

    
1864
                    /* This is somewhat linux specific I guess */
1865
                    snprintf(ps_cmd, sizeof(ps_cmd),
1866
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1867
                             stream->pid);
1868

    
1869
                    pid_stat = popen(ps_cmd, "r");
1870
                    if (pid_stat) {
1871
                        char cpuperc[10];
1872
                        char cpuused[64];
1873

    
1874
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1875
                                   cpuused) == 2) {
1876
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1877
                                         cpuperc, cpuused);
1878
                        }
1879
                        fclose(pid_stat);
1880
                    }
1881
                }
1882
#endif
1883

    
1884
                url_fprintf(pb, "<p>");
1885
            }
1886
            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");
1887

    
1888
            for (i = 0; i < stream->nb_streams; i++) {
1889
                AVStream *st = stream->streams[i];
1890
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1891
                const char *type = "unknown";
1892
                char parameters[64];
1893

    
1894
                parameters[0] = 0;
1895

    
1896
                switch(st->codec->codec_type) {
1897
                case AVMEDIA_TYPE_AUDIO:
1898
                    type = "audio";
1899
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1900
                    break;
1901
                case AVMEDIA_TYPE_VIDEO:
1902
                    type = "video";
1903
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1904
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1905
                    break;
1906
                default:
1907
                    abort();
1908
                }
1909
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1910
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1911
            }
1912
            url_fprintf(pb, "</table>\n");
1913

    
1914
        }
1915
        stream = stream->next;
1916
    }
1917

    
1918
    /* connection status */
1919
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1920

    
1921
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1922
                 nb_connections, nb_max_connections);
1923

    
1924
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1925
                 current_bandwidth, max_bandwidth);
1926

    
1927
    url_fprintf(pb, "<table>\n");
1928
    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");
1929
    c1 = first_http_ctx;
1930
    i = 0;
1931
    while (c1 != NULL) {
1932
        int bitrate;
1933
        int j;
1934

    
1935
        bitrate = 0;
1936
        if (c1->stream) {
1937
            for (j = 0; j < c1->stream->nb_streams; j++) {
1938
                if (!c1->stream->feed)
1939
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1940
                else if (c1->feed_streams[j] >= 0)
1941
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1942
            }
1943
        }
1944

    
1945
        i++;
1946
        p = inet_ntoa(c1->from_addr.sin_addr);
1947
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1948
                    i,
1949
                    c1->stream ? c1->stream->filename : "",
1950
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1951
                    p,
1952
                    c1->protocol,
1953
                    http_state[c1->state]);
1954
        fmt_bytecount(pb, bitrate);
1955
        url_fprintf(pb, "<td align=right>");
1956
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1957
        url_fprintf(pb, "<td align=right>");
1958
        fmt_bytecount(pb, c1->data_count);
1959
        url_fprintf(pb, "\n");
1960
        c1 = c1->next;
1961
    }
1962
    url_fprintf(pb, "</table>\n");
1963

    
1964
    /* date */
1965
    ti = time(NULL);
1966
    p = ctime(&ti);
1967
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1968
    url_fprintf(pb, "</body>\n</html>\n");
1969

    
1970
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1971
    c->buffer_ptr = c->pb_buffer;
1972
    c->buffer_end = c->pb_buffer + len;
1973
}
1974

    
1975
/* check if the parser needs to be opened for stream i */
1976
static void open_parser(AVFormatContext *s, int i)
1977
{
1978
    AVStream *st = s->streams[i];
1979
    AVCodec *codec;
1980

    
1981
    if (!st->codec->codec) {
1982
        codec = avcodec_find_decoder(st->codec->codec_id);
1983
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1984
            st->codec->parse_only = 1;
1985
            if (avcodec_open(st->codec, codec) < 0)
1986
                st->codec->parse_only = 0;
1987
        }
1988
    }
1989
}
1990

    
1991
static int open_input_stream(HTTPContext *c, const char *info)
1992
{
1993
    char buf[128];
1994
    char input_filename[1024];
1995
    AVFormatContext *s;
1996
    int buf_size, i, ret;
1997
    int64_t stream_pos;
1998

    
1999
    /* find file name */
2000
    if (c->stream->feed) {
2001
        strcpy(input_filename, c->stream->feed->feed_filename);
2002
        buf_size = FFM_PACKET_SIZE;
2003
        /* compute position (absolute time) */
2004
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2005
            stream_pos = parse_date(buf, 0);
2006
            if (stream_pos == INT64_MIN)
2007
                return -1;
2008
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
2009
            int prebuffer = strtol(buf, 0, 10);
2010
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2011
        } else
2012
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2013
    } else {
2014
        strcpy(input_filename, c->stream->feed_filename);
2015
        buf_size = 0;
2016
        /* compute position (relative time) */
2017
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2018
            stream_pos = parse_date(buf, 1);
2019
            if (stream_pos == INT64_MIN)
2020
                return -1;
2021
        } else
2022
            stream_pos = 0;
2023
    }
2024
    if (input_filename[0] == '\0')
2025
        return -1;
2026

    
2027
    /* open stream */
2028
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2029
                                  buf_size, c->stream->ap_in)) < 0) {
2030
        http_log("could not open %s: %d\n", input_filename, ret);
2031
        return -1;
2032
    }
2033
    s->flags |= AVFMT_FLAG_GENPTS;
2034
    c->fmt_in = s;
2035
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2036
        http_log("Could not find stream info '%s'\n", input_filename);
2037
        av_close_input_file(s);
2038
        return -1;
2039
    }
2040

    
2041
    /* open each parser */
2042
    for(i=0;i<s->nb_streams;i++)
2043
        open_parser(s, i);
2044

    
2045
    /* choose stream as clock source (we favorize video stream if
2046
       present) for packet sending */
2047
    c->pts_stream_index = 0;
2048
    for(i=0;i<c->stream->nb_streams;i++) {
2049
        if (c->pts_stream_index == 0 &&
2050
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2051
            c->pts_stream_index = i;
2052
        }
2053
    }
2054

    
2055
#if 1
2056
    if (c->fmt_in->iformat->read_seek)
2057
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2058
#endif
2059
    /* set the start time (needed for maxtime and RTP packet timing) */
2060
    c->start_time = cur_time;
2061
    c->first_pts = AV_NOPTS_VALUE;
2062
    return 0;
2063
}
2064

    
2065
/* return the server clock (in us) */
2066
static int64_t get_server_clock(HTTPContext *c)
2067
{
2068
    /* compute current pts value from system time */
2069
    return (cur_time - c->start_time) * 1000;
2070
}
2071

    
2072
/* return the estimated time at which the current packet must be sent
2073
   (in us) */
2074
static int64_t get_packet_send_clock(HTTPContext *c)
2075
{
2076
    int bytes_left, bytes_sent, frame_bytes;
2077

    
2078
    frame_bytes = c->cur_frame_bytes;
2079
    if (frame_bytes <= 0)
2080
        return c->cur_pts;
2081
    else {
2082
        bytes_left = c->buffer_end - c->buffer_ptr;
2083
        bytes_sent = frame_bytes - bytes_left;
2084
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2085
    }
2086
}
2087

    
2088

    
2089
static int http_prepare_data(HTTPContext *c)
2090
{
2091
    int i, len, ret;
2092
    AVFormatContext *ctx;
2093

    
2094
    av_freep(&c->pb_buffer);
2095
    switch(c->state) {
2096
    case HTTPSTATE_SEND_DATA_HEADER:
2097
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2098
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2099
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2100
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2101
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2102

    
2103
        for(i=0;i<c->stream->nb_streams;i++) {
2104
            AVStream *st;
2105
            AVStream *src;
2106
            st = av_mallocz(sizeof(AVStream));
2107
            c->fmt_ctx.streams[i] = st;
2108
            /* if file or feed, then just take streams from FFStream struct */
2109
            if (!c->stream->feed ||
2110
                c->stream->feed == c->stream)
2111
                src = c->stream->streams[i];
2112
            else
2113
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2114

    
2115
            *st = *src;
2116
            st->priv_data = 0;
2117
            st->codec->frame_number = 0; /* XXX: should be done in
2118
                                           AVStream, not in codec */
2119
        }
2120
        /* set output format parameters */
2121
        c->fmt_ctx.oformat = c->stream->fmt;
2122
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2123

    
2124
        c->got_key_frame = 0;
2125

    
2126
        /* prepare header and save header data in a stream */
2127
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2128
            /* XXX: potential leak */
2129
            return -1;
2130
        }
2131
        c->fmt_ctx.pb->is_streamed = 1;
2132

    
2133
        /*
2134
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2135
         * Default value from FFmpeg
2136
         * Try to set it use configuration option
2137
         */
2138
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2139
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2140

    
2141
        av_set_parameters(&c->fmt_ctx, NULL);
2142
        if (av_write_header(&c->fmt_ctx) < 0) {
2143
            http_log("Error writing output header\n");
2144
            return -1;
2145
        }
2146

    
2147
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2148
        c->buffer_ptr = c->pb_buffer;
2149
        c->buffer_end = c->pb_buffer + len;
2150

    
2151
        c->state = HTTPSTATE_SEND_DATA;
2152
        c->last_packet_sent = 0;
2153
        break;
2154
    case HTTPSTATE_SEND_DATA:
2155
        /* find a new packet */
2156
        /* read a packet from the input stream */
2157
        if (c->stream->feed)
2158
            ffm_set_write_index(c->fmt_in,
2159
                                c->stream->feed->feed_write_index,
2160
                                c->stream->feed->feed_size);
2161

    
2162
        if (c->stream->max_time &&
2163
            c->stream->max_time + c->start_time - cur_time < 0)
2164
            /* We have timed out */
2165
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2166
        else {
2167
            AVPacket pkt;
2168
        redo:
2169
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2170
                if (c->stream->feed && c->stream->feed->feed_opened) {
2171
                    /* if coming from feed, it means we reached the end of the
2172
                       ffm file, so must wait for more data */
2173
                    c->state = HTTPSTATE_WAIT_FEED;
2174
                    return 1; /* state changed */
2175
                } else {
2176
                    if (c->stream->loop) {
2177
                        av_close_input_file(c->fmt_in);
2178
                        c->fmt_in = NULL;
2179
                        if (open_input_stream(c, "") < 0)
2180
                            goto no_loop;
2181
                        goto redo;
2182
                    } else {
2183
                    no_loop:
2184
                        /* must send trailer now because eof or error */
2185
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2186
                    }
2187
                }
2188
            } else {
2189
                int source_index = pkt.stream_index;
2190
                /* update first pts if needed */
2191
                if (c->first_pts == AV_NOPTS_VALUE) {
2192
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2193
                    c->start_time = cur_time;
2194
                }
2195
                /* send it to the appropriate stream */
2196
                if (c->stream->feed) {
2197
                    /* if coming from a feed, select the right stream */
2198
                    if (c->switch_pending) {
2199
                        c->switch_pending = 0;
2200
                        for(i=0;i<c->stream->nb_streams;i++) {
2201
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2202
                                if (pkt.flags & PKT_FLAG_KEY)
2203
                                    do_switch_stream(c, i);
2204
                            if (c->switch_feed_streams[i] >= 0)
2205
                                c->switch_pending = 1;
2206
                        }
2207
                    }
2208
                    for(i=0;i<c->stream->nb_streams;i++) {
2209
                        if (c->feed_streams[i] == pkt.stream_index) {
2210
                            AVStream *st = c->fmt_in->streams[source_index];
2211
                            pkt.stream_index = i;
2212
                            if (pkt.flags & PKT_FLAG_KEY &&
2213
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2214
                                 c->stream->nb_streams == 1))
2215
                                c->got_key_frame = 1;
2216
                            if (!c->stream->send_on_key || c->got_key_frame)
2217
                                goto send_it;
2218
                        }
2219
                    }
2220
                } else {
2221
                    AVCodecContext *codec;
2222
                    AVStream *ist, *ost;
2223
                send_it:
2224
                    ist = c->fmt_in->streams[source_index];
2225
                    /* specific handling for RTP: we use several
2226
                       output stream (one for each RTP
2227
                       connection). XXX: need more abstract handling */
2228
                    if (c->is_packetized) {
2229
                        /* compute send time and duration */
2230
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2231
                        if (ist->start_time != AV_NOPTS_VALUE)
2232
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2233
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2234
                        /* find RTP context */
2235
                        c->packet_stream_index = pkt.stream_index;
2236
                        ctx = c->rtp_ctx[c->packet_stream_index];
2237
                        if(!ctx) {
2238
                            av_free_packet(&pkt);
2239
                            break;
2240
                        }
2241
                        codec = ctx->streams[0]->codec;
2242
                        /* only one stream per RTP connection */
2243
                        pkt.stream_index = 0;
2244
                    } else {
2245
                        ctx = &c->fmt_ctx;
2246
                        /* Fudge here */
2247
                        codec = ctx->streams[pkt.stream_index]->codec;
2248
                    }
2249

    
2250
                    if (c->is_packetized) {
2251
                        int max_packet_size;
2252
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2253
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2254
                        else
2255
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2256
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2257
                    } else {
2258
                        ret = url_open_dyn_buf(&ctx->pb);
2259
                    }
2260
                    if (ret < 0) {
2261
                        /* XXX: potential leak */
2262
                        return -1;
2263
                    }
2264
                    ost = ctx->streams[pkt.stream_index];
2265

    
2266
                    ctx->pb->is_streamed = 1;
2267
                    if (pkt.dts != AV_NOPTS_VALUE)
2268
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2269
                    if (pkt.pts != AV_NOPTS_VALUE)
2270
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2271
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2272
                    if (av_write_frame(ctx, &pkt) < 0) {
2273
                        http_log("Error writing frame to output\n");
2274
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2275
                    }
2276

    
2277
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2278
                    c->cur_frame_bytes = len;
2279
                    c->buffer_ptr = c->pb_buffer;
2280
                    c->buffer_end = c->pb_buffer + len;
2281

    
2282
                    codec->frame_number++;
2283
                    if (len == 0) {
2284
                        av_free_packet(&pkt);
2285
                        goto redo;
2286
                    }
2287
                }
2288
                av_free_packet(&pkt);
2289
            }
2290
        }
2291
        break;
2292
    default:
2293
    case HTTPSTATE_SEND_DATA_TRAILER:
2294
        /* last packet test ? */
2295
        if (c->last_packet_sent || c->is_packetized)
2296
            return -1;
2297
        ctx = &c->fmt_ctx;
2298
        /* prepare header */
2299
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2300
            /* XXX: potential leak */
2301
            return -1;
2302
        }
2303
        c->fmt_ctx.pb->is_streamed = 1;
2304
        av_write_trailer(ctx);
2305
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2306
        c->buffer_ptr = c->pb_buffer;
2307
        c->buffer_end = c->pb_buffer + len;
2308

    
2309
        c->last_packet_sent = 1;
2310
        break;
2311
    }
2312
    return 0;
2313
}
2314

    
2315
/* should convert the format at the same time */
2316
/* send data starting at c->buffer_ptr to the output connection
2317
   (either UDP or TCP connection) */
2318
static int http_send_data(HTTPContext *c)
2319
{
2320
    int len, ret;
2321

    
2322
    for(;;) {
2323
        if (c->buffer_ptr >= c->buffer_end) {
2324
            ret = http_prepare_data(c);
2325
            if (ret < 0)
2326
                return -1;
2327
            else if (ret != 0)
2328
                /* state change requested */
2329
                break;
2330
        } else {
2331
            if (c->is_packetized) {
2332
                /* RTP data output */
2333
                len = c->buffer_end - c->buffer_ptr;
2334
                if (len < 4) {
2335
                    /* fail safe - should never happen */
2336
                fail1:
2337
                    c->buffer_ptr = c->buffer_end;
2338
                    return 0;
2339
                }
2340
                len = (c->buffer_ptr[0] << 24) |
2341
                    (c->buffer_ptr[1] << 16) |
2342
                    (c->buffer_ptr[2] << 8) |
2343
                    (c->buffer_ptr[3]);
2344
                if (len > (c->buffer_end - c->buffer_ptr))
2345
                    goto fail1;
2346
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2347
                    /* nothing to send yet: we can wait */
2348
                    return 0;
2349
                }
2350

    
2351
                c->data_count += len;
2352
                update_datarate(&c->datarate, c->data_count);
2353
                if (c->stream)
2354
                    c->stream->bytes_served += len;
2355

    
2356
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2357
                    /* RTP packets are sent inside the RTSP TCP connection */
2358
                    ByteIOContext *pb;
2359
                    int interleaved_index, size;
2360
                    uint8_t header[4];
2361
                    HTTPContext *rtsp_c;
2362

    
2363
                    rtsp_c = c->rtsp_c;
2364
                    /* if no RTSP connection left, error */
2365
                    if (!rtsp_c)
2366
                        return -1;
2367
                    /* if already sending something, then wait. */
2368
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2369
                        break;
2370
                    if (url_open_dyn_buf(&pb) < 0)
2371
                        goto fail1;
2372
                    interleaved_index = c->packet_stream_index * 2;
2373
                    /* RTCP packets are sent at odd indexes */
2374
                    if (c->buffer_ptr[1] == 200)
2375
                        interleaved_index++;
2376
                    /* write RTSP TCP header */
2377
                    header[0] = '$';
2378
                    header[1] = interleaved_index;
2379
                    header[2] = len >> 8;
2380
                    header[3] = len;
2381
                    put_buffer(pb, header, 4);
2382
                    /* write RTP packet data */
2383
                    c->buffer_ptr += 4;
2384
                    put_buffer(pb, c->buffer_ptr, len);
2385
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2386
                    /* prepare asynchronous TCP sending */
2387
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2388
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2389
                    c->buffer_ptr += len;
2390

    
2391
                    /* send everything we can NOW */
2392
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2393
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2394
                    if (len > 0)
2395
                        rtsp_c->packet_buffer_ptr += len;
2396
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2397
                        /* if we could not send all the data, we will
2398
                           send it later, so a new state is needed to
2399
                           "lock" the RTSP TCP connection */
2400
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2401
                        break;
2402
                    } else
2403
                        /* all data has been sent */
2404
                        av_freep(&c->packet_buffer);
2405
                } else {
2406
                    /* send RTP packet directly in UDP */
2407
                    c->buffer_ptr += 4;
2408
                    url_write(c->rtp_handles[c->packet_stream_index],
2409
                              c->buffer_ptr, len);
2410
                    c->buffer_ptr += len;
2411
                    /* here we continue as we can send several packets per 10 ms slot */
2412
                }
2413
            } else {
2414
                /* TCP data output */
2415
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2416
                if (len < 0) {
2417
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2418
                        ff_neterrno() != FF_NETERROR(EINTR))
2419
                        /* error : close connection */
2420
                        return -1;
2421
                    else
2422
                        return 0;
2423
                } else
2424
                    c->buffer_ptr += len;
2425

    
2426
                c->data_count += len;
2427
                update_datarate(&c->datarate, c->data_count);
2428
                if (c->stream)
2429
                    c->stream->bytes_served += len;
2430
                break;
2431
            }
2432
        }
2433
    } /* for(;;) */
2434
    return 0;
2435
}
2436

    
2437
static int http_start_receive_data(HTTPContext *c)
2438
{
2439
    int fd;
2440

    
2441
    if (c->stream->feed_opened)
2442
        return -1;
2443

    
2444
    /* Don't permit writing to this one */
2445
    if (c->stream->readonly)
2446
        return -1;
2447

    
2448
    /* open feed */
2449
    fd = open(c->stream->feed_filename, O_RDWR);
2450
    if (fd < 0) {
2451
        http_log("Error opening feeder file: %s\n", strerror(errno));
2452
        return -1;
2453
    }
2454
    c->feed_fd = fd;
2455

    
2456
    if (c->stream->truncate) {
2457
        /* truncate feed file */
2458
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2459
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2460
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2461
    } else {
2462
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2463
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2464
            return -1;
2465
        }
2466
    }
2467

    
2468
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2469
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2470
    lseek(fd, 0, SEEK_SET);
2471

    
2472
    /* init buffer input */
2473
    c->buffer_ptr = c->buffer;
2474
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2475
    c->stream->feed_opened = 1;
2476
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2477
    return 0;
2478
}
2479

    
2480
static int http_receive_data(HTTPContext *c)
2481
{
2482
    HTTPContext *c1;
2483
    int len, loop_run = 0;
2484

    
2485
    while (c->chunked_encoding && !c->chunk_size &&
2486
           c->buffer_end > c->buffer_ptr) {
2487
        /* read chunk header, if present */
2488
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2489

    
2490
        if (len < 0) {
2491
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2492
                ff_neterrno() != FF_NETERROR(EINTR))
2493
                /* error : close connection */
2494
                goto fail;
2495
        } else if (len == 0) {
2496
            /* end of connection : close it */
2497
            goto fail;
2498
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2499
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2500
            c->chunk_size = strtol(c->buffer, 0, 16);
2501
            if (c->chunk_size == 0) // end of stream
2502
                goto fail;
2503
            c->buffer_ptr = c->buffer;
2504
            break;
2505
        } else if (++loop_run > 10) {
2506
            /* no chunk header, abort */
2507
            goto fail;
2508
        } else {
2509
            c->buffer_ptr++;
2510
        }
2511
    }
2512

    
2513
    if (c->buffer_end > c->buffer_ptr) {
2514
        len = recv(c->fd, c->buffer_ptr,
2515
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2516
        if (len < 0) {
2517
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2518
                ff_neterrno() != FF_NETERROR(EINTR))
2519
                /* error : close connection */
2520
                goto fail;
2521
        } else if (len == 0)
2522
            /* end of connection : close it */
2523
            goto fail;
2524
        else {
2525
            c->chunk_size -= len;
2526
            c->buffer_ptr += len;
2527
            c->data_count += len;
2528
            update_datarate(&c->datarate, c->data_count);
2529
        }
2530
    }
2531

    
2532
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2533
        if (c->buffer[0] != 'f' ||
2534
            c->buffer[1] != 'm') {
2535
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2536
            goto fail;
2537
        }
2538
    }
2539

    
2540
    if (c->buffer_ptr >= c->buffer_end) {
2541
        FFStream *feed = c->stream;
2542
        /* a packet has been received : write it in the store, except
2543
           if header */
2544
        if (c->data_count > FFM_PACKET_SIZE) {
2545

    
2546
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2547
            /* XXX: use llseek or url_seek */
2548
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2549
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2550
                http_log("Error writing to feed file: %s\n", strerror(errno));
2551
                goto fail;
2552
            }
2553

    
2554
            feed->feed_write_index += FFM_PACKET_SIZE;
2555
            /* update file size */
2556
            if (feed->feed_write_index > c->stream->feed_size)
2557
                feed->feed_size = feed->feed_write_index;
2558

    
2559
            /* handle wrap around if max file size reached */
2560
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2561
                feed->feed_write_index = FFM_PACKET_SIZE;
2562

    
2563
            /* write index */
2564
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2565
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2566
                goto fail;
2567
            }
2568

    
2569
            /* wake up any waiting connections */
2570
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2571
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2572
                    c1->stream->feed == c->stream->feed)
2573
                    c1->state = HTTPSTATE_SEND_DATA;
2574
            }
2575
        } else {
2576
            /* We have a header in our hands that contains useful data */
2577
            AVFormatContext *s = NULL;
2578
            ByteIOContext *pb;
2579
            AVInputFormat *fmt_in;
2580
            int i;
2581

    
2582
            /* use feed output format name to find corresponding input format */
2583
            fmt_in = av_find_input_format(feed->fmt->name);
2584
            if (!fmt_in)
2585
                goto fail;
2586

    
2587
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2588
            pb->is_streamed = 1;
2589

    
2590
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2591
                av_free(pb);
2592
                goto fail;
2593
            }
2594

    
2595
            /* Now we have the actual streams */
2596
            if (s->nb_streams != feed->nb_streams) {
2597
                av_close_input_stream(s);
2598
                av_free(pb);
2599
                http_log("Feed '%s' stream number does not match registered feed\n",
2600
                         c->stream->feed_filename);
2601
                goto fail;
2602
            }
2603

    
2604
            for (i = 0; i < s->nb_streams; i++) {
2605
                AVStream *fst = feed->streams[i];
2606
                AVStream *st = s->streams[i];
2607
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2608
                if (fst->codec->extradata_size) {
2609
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2610
                    if (!fst->codec->extradata)
2611
                        goto fail;
2612
                    memcpy(fst->codec->extradata, st->codec->extradata,
2613
                           fst->codec->extradata_size);
2614
                }
2615
            }
2616

    
2617
            av_close_input_stream(s);
2618
            av_free(pb);
2619
        }
2620
        c->buffer_ptr = c->buffer;
2621
    }
2622

    
2623
    return 0;
2624
 fail:
2625
    c->stream->feed_opened = 0;
2626
    close(c->feed_fd);
2627
    /* wake up any waiting connections to stop waiting for feed */
2628
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2629
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2630
            c1->stream->feed == c->stream->feed)
2631
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2632
    }
2633
    return -1;
2634
}
2635

    
2636
/********************************************************************/
2637
/* RTSP handling */
2638

    
2639
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2640
{
2641
    const char *str;
2642
    time_t ti;
2643
    char *p;
2644
    char buf2[32];
2645

    
2646
    switch(error_number) {
2647
    case RTSP_STATUS_OK:
2648
        str = "OK";
2649
        break;
2650
    case RTSP_STATUS_METHOD:
2651
        str = "Method Not Allowed";
2652
        break;
2653
    case RTSP_STATUS_BANDWIDTH:
2654
        str = "Not Enough Bandwidth";
2655
        break;
2656
    case RTSP_STATUS_SESSION:
2657
        str = "Session Not Found";
2658
        break;
2659
    case RTSP_STATUS_STATE:
2660
        str = "Method Not Valid in This State";
2661
        break;
2662
    case RTSP_STATUS_AGGREGATE:
2663
        str = "Aggregate operation not allowed";
2664
        break;
2665
    case RTSP_STATUS_ONLY_AGGREGATE:
2666
        str = "Only aggregate operation allowed";
2667
        break;
2668
    case RTSP_STATUS_TRANSPORT:
2669
        str = "Unsupported transport";
2670
        break;
2671
    case RTSP_STATUS_INTERNAL:
2672
        str = "Internal Server Error";
2673
        break;
2674
    case RTSP_STATUS_SERVICE:
2675
        str = "Service Unavailable";
2676
        break;
2677
    case RTSP_STATUS_VERSION:
2678
        str = "RTSP Version not supported";
2679
        break;
2680
    default:
2681
        str = "Unknown Error";
2682
        break;
2683
    }
2684

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

    
2688
    /* output GMT time */
2689
    ti = time(NULL);
2690
    p = ctime(&ti);
2691
    strcpy(buf2, p);
2692
    p = buf2 + strlen(p) - 1;
2693
    if (*p == '\n')
2694
        *p = '\0';
2695
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2696
}
2697

    
2698
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2699
{
2700
    rtsp_reply_header(c, error_number);
2701
    url_fprintf(c->pb, "\r\n");
2702
}
2703

    
2704
static int rtsp_parse_request(HTTPContext *c)
2705
{
2706
    const char *p, *p1, *p2;
2707
    char cmd[32];
2708
    char url[1024];
2709
    char protocol[32];
2710
    char line[1024];
2711
    int len;
2712
    RTSPMessageHeader header1, *header = &header1;
2713

    
2714
    c->buffer_ptr[0] = '\0';
2715
    p = c->buffer;
2716

    
2717
    get_word(cmd, sizeof(cmd), &p);
2718
    get_word(url, sizeof(url), &p);
2719
    get_word(protocol, sizeof(protocol), &p);
2720

    
2721
    av_strlcpy(c->method, cmd, sizeof(c->method));
2722
    av_strlcpy(c->url, url, sizeof(c->url));
2723
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2724

    
2725
    if (url_open_dyn_buf(&c->pb) < 0) {
2726
        /* XXX: cannot do more */
2727
        c->pb = NULL; /* safety */
2728
        return -1;
2729
    }
2730

    
2731
    /* check version name */
2732
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2733
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2734
        goto the_end;
2735
    }
2736

    
2737
    /* parse each header line */
2738
    memset(header, 0, sizeof(*header));
2739
    /* skip to next line */
2740
    while (*p != '\n' && *p != '\0')
2741
        p++;
2742
    if (*p == '\n')
2743
        p++;
2744
    while (*p != '\0') {
2745
        p1 = strchr(p, '\n');
2746
        if (!p1)
2747
            break;
2748
        p2 = p1;
2749
        if (p2 > p && p2[-1] == '\r')
2750
            p2--;
2751
        /* skip empty line */
2752
        if (p2 == p)
2753
            break;
2754
        len = p2 - p;
2755
        if (len > sizeof(line) - 1)
2756
            len = sizeof(line) - 1;
2757
        memcpy(line, p, len);
2758
        line[len] = '\0';
2759
        ff_rtsp_parse_line(header, line, NULL);
2760
        p = p1 + 1;
2761
    }
2762

    
2763
    /* handle sequence number */
2764
    c->seq = header->seq;
2765

    
2766
    if (!strcmp(cmd, "DESCRIBE"))
2767
        rtsp_cmd_describe(c, url);
2768
    else if (!strcmp(cmd, "OPTIONS"))
2769
        rtsp_cmd_options(c, url);
2770
    else if (!strcmp(cmd, "SETUP"))
2771
        rtsp_cmd_setup(c, url, header);
2772
    else if (!strcmp(cmd, "PLAY"))
2773
        rtsp_cmd_play(c, url, header);
2774
    else if (!strcmp(cmd, "PAUSE"))
2775
        rtsp_cmd_pause(c, url, header);
2776
    else if (!strcmp(cmd, "TEARDOWN"))
2777
        rtsp_cmd_teardown(c, url, header);
2778
    else
2779
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2780

    
2781
 the_end:
2782
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2783
    c->pb = NULL; /* safety */
2784
    if (len < 0) {
2785
        /* XXX: cannot do more */
2786
        return -1;
2787
    }
2788
    c->buffer_ptr = c->pb_buffer;
2789
    c->buffer_end = c->pb_buffer + len;
2790
    c->state = RTSPSTATE_SEND_REPLY;
2791
    return 0;
2792
}
2793

    
2794
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2795
                                   struct in_addr my_ip)
2796
{
2797
    AVFormatContext *avc;
2798
    AVStream avs[MAX_STREAMS];
2799
    int i;
2800

    
2801
    avc =  avformat_alloc_context();
2802
    if (avc == NULL) {
2803
        return -1;
2804
    }
2805
    av_metadata_set(&avc->metadata, "title",
2806
                    stream->title[0] ? stream->title : "No Title");
2807
    avc->nb_streams = stream->nb_streams;
2808
    if (stream->is_multicast) {
2809
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2810
                 inet_ntoa(stream->multicast_ip),
2811
                 stream->multicast_port, stream->multicast_ttl);
2812
    }
2813

    
2814
    for(i = 0; i < stream->nb_streams; i++) {
2815
        avc->streams[i] = &avs[i];
2816
        avc->streams[i]->codec = stream->streams[i]->codec;
2817
    }
2818
    *pbuffer = av_mallocz(2048);
2819
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2820
    av_free(avc);
2821

    
2822
    return strlen(*pbuffer);
2823
}
2824

    
2825
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2826
{
2827
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2828
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2829
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2830
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2831
    url_fprintf(c->pb, "\r\n");
2832
}
2833

    
2834
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2835
{
2836
    FFStream *stream;
2837
    char path1[1024];
2838
    const char *path;
2839
    uint8_t *content;
2840
    int content_length, len;
2841
    struct sockaddr_in my_addr;
2842

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

    
2849
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2850
        if (!stream->is_feed &&
2851
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2852
            !strcmp(path, stream->filename)) {
2853
            goto found;
2854
        }
2855
    }
2856
    /* no stream found */
2857
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2858
    return;
2859

    
2860
 found:
2861
    /* prepare the media description in sdp format */
2862

    
2863
    /* get the host IP */
2864
    len = sizeof(my_addr);
2865
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2866
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2867
    if (content_length < 0) {
2868
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2869
        return;
2870
    }
2871
    rtsp_reply_header(c, RTSP_STATUS_OK);
2872
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2873
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2874
    url_fprintf(c->pb, "\r\n");
2875
    put_buffer(c->pb, content, content_length);
2876
}
2877

    
2878
static HTTPContext *find_rtp_session(const char *session_id)
2879
{
2880
    HTTPContext *c;
2881

    
2882
    if (session_id[0] == '\0')
2883
        return NULL;
2884

    
2885
    for(c = first_http_ctx; c != NULL; c = c->next) {
2886
        if (!strcmp(c->session_id, session_id))
2887
            return c;
2888
    }
2889
    return NULL;
2890
}
2891

    
2892
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2893
{
2894
    RTSPTransportField *th;
2895
    int i;
2896

    
2897
    for(i=0;i<h->nb_transports;i++) {
2898
        th = &h->transports[i];
2899
        if (th->lower_transport == lower_transport)
2900
            return th;
2901
    }
2902
    return NULL;
2903
}
2904

    
2905
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2906
                           RTSPMessageHeader *h)
2907
{
2908
    FFStream *stream;
2909
    int stream_index, port;
2910
    char buf[1024];
2911
    char path1[1024];
2912
    const char *path;
2913
    HTTPContext *rtp_c;
2914
    RTSPTransportField *th;
2915
    struct sockaddr_in dest_addr;
2916
    RTSPActionServerSetup setup;
2917

    
2918
    /* find which url is asked */
2919
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2920
    path = path1;
2921
    if (*path == '/')
2922
        path++;
2923

    
2924
    /* now check each stream */
2925
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2926
        if (!stream->is_feed &&
2927
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2928
            /* accept aggregate filenames only if single stream */
2929
            if (!strcmp(path, stream->filename)) {
2930
                if (stream->nb_streams != 1) {
2931
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2932
                    return;
2933
                }
2934
                stream_index = 0;
2935
                goto found;
2936
            }
2937

    
2938
            for(stream_index = 0; stream_index < stream->nb_streams;
2939
                stream_index++) {
2940
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2941
                         stream->filename, stream_index);
2942
                if (!strcmp(path, buf))
2943
                    goto found;
2944
            }
2945
        }
2946
    }
2947
    /* no stream found */
2948
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2949
    return;
2950
 found:
2951

    
2952
    /* generate session id if needed */
2953
    if (h->session_id[0] == '\0')
2954
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2955
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2956

    
2957
    /* find rtp session, and create it if none found */
2958
    rtp_c = find_rtp_session(h->session_id);
2959
    if (!rtp_c) {
2960
        /* always prefer UDP */
2961
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2962
        if (!th) {
2963
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2964
            if (!th) {
2965
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2966
                return;
2967
            }
2968
        }
2969

    
2970
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2971
                                   th->lower_transport);
2972
        if (!rtp_c) {
2973
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2974
            return;
2975
        }
2976

    
2977
        /* open input stream */
2978
        if (open_input_stream(rtp_c, "") < 0) {
2979
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2980
            return;
2981
        }
2982
    }
2983

    
2984
    /* test if stream is OK (test needed because several SETUP needs
2985
       to be done for a given file) */
2986
    if (rtp_c->stream != stream) {
2987
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2988
        return;
2989
    }
2990

    
2991
    /* test if stream is already set up */
2992
    if (rtp_c->rtp_ctx[stream_index]) {
2993
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2994
        return;
2995
    }
2996

    
2997
    /* check transport */
2998
    th = find_transport(h, rtp_c->rtp_protocol);
2999
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3000
                th->client_port_min <= 0)) {
3001
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3002
        return;
3003
    }
3004

    
3005
    /* setup default options */
3006
    setup.transport_option[0] = '\0';
3007
    dest_addr = rtp_c->from_addr;
3008
    dest_addr.sin_port = htons(th->client_port_min);
3009

    
3010
    /* setup stream */
3011
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3012
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3013
        return;
3014
    }
3015

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

    
3021
    switch(rtp_c->rtp_protocol) {
3022
    case RTSP_LOWER_TRANSPORT_UDP:
3023
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
3024
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3025
                    "client_port=%d-%d;server_port=%d-%d",
3026
                    th->client_port_min, th->client_port_min + 1,
3027
                    port, port + 1);
3028
        break;
3029
    case RTSP_LOWER_TRANSPORT_TCP:
3030
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3031
                    stream_index * 2, stream_index * 2 + 1);
3032
        break;
3033
    default:
3034
        break;
3035
    }
3036
    if (setup.transport_option[0] != '\0')
3037
        url_fprintf(c->pb, ";%s", setup.transport_option);
3038
    url_fprintf(c->pb, "\r\n");
3039

    
3040

    
3041
    url_fprintf(c->pb, "\r\n");
3042
}
3043

    
3044

    
3045
/* find an rtp connection by using the session ID. Check consistency
3046
   with filename */
3047
static HTTPContext *find_rtp_session_with_url(const char *url,
3048
                                              const char *session_id)
3049
{
3050
    HTTPContext *rtp_c;
3051
    char path1[1024];
3052
    const char *path;
3053
    char buf[1024];
3054
    int s;
3055

    
3056
    rtp_c = find_rtp_session(session_id);
3057
    if (!rtp_c)
3058
        return NULL;
3059

    
3060
    /* find which url is asked */
3061
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3062
    path = path1;
3063
    if (*path == '/')
3064
        path++;
3065
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3066
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3067
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3068
        rtp_c->stream->filename, s);
3069
      if(!strncmp(path, buf, sizeof(buf))) {
3070
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3071
        return rtp_c;
3072
      }
3073
    }
3074
    return NULL;
3075
}
3076

    
3077
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3078
{
3079
    HTTPContext *rtp_c;
3080

    
3081
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3082
    if (!rtp_c) {
3083
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3084
        return;
3085
    }
3086

    
3087
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3088
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3089
        rtp_c->state != HTTPSTATE_READY) {
3090
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3091
        return;
3092
    }
3093

    
3094
    rtp_c->state = HTTPSTATE_SEND_DATA;
3095

    
3096
    /* now everything is OK, so we can send the connection parameters */
3097
    rtsp_reply_header(c, RTSP_STATUS_OK);
3098
    /* session ID */
3099
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3100
    url_fprintf(c->pb, "\r\n");
3101
}
3102

    
3103
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3104
{
3105
    HTTPContext *rtp_c;
3106

    
3107
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3108
    if (!rtp_c) {
3109
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3110
        return;
3111
    }
3112

    
3113
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3114
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3115
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3116
        return;
3117
    }
3118

    
3119
    rtp_c->state = HTTPSTATE_READY;
3120
    rtp_c->first_pts = AV_NOPTS_VALUE;
3121
    /* now everything is OK, so we can send the connection parameters */
3122
    rtsp_reply_header(c, RTSP_STATUS_OK);
3123
    /* session ID */
3124
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3125
    url_fprintf(c->pb, "\r\n");
3126
}
3127

    
3128
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3129
{
3130
    HTTPContext *rtp_c;
3131
    char session_id[32];
3132

    
3133
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3134
    if (!rtp_c) {
3135
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3136
        return;
3137
    }
3138

    
3139
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3140

    
3141
    /* abort the session */
3142
    close_connection(rtp_c);
3143

    
3144
    /* now everything is OK, so we can send the connection parameters */
3145
    rtsp_reply_header(c, RTSP_STATUS_OK);
3146
    /* session ID */
3147
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3148
    url_fprintf(c->pb, "\r\n");
3149
}
3150

    
3151

    
3152
/********************************************************************/
3153
/* RTP handling */
3154

    
3155
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3156
                                       FFStream *stream, const char *session_id,
3157
                                       enum RTSPLowerTransport rtp_protocol)
3158
{
3159
    HTTPContext *c = NULL;
3160
    const char *proto_str;
3161

    
3162
    /* XXX: should output a warning page when coming
3163
       close to the connection limit */
3164
    if (nb_connections >= nb_max_connections)
3165
        goto fail;
3166

    
3167
    /* add a new connection */
3168
    c = av_mallocz(sizeof(HTTPContext));
3169
    if (!c)
3170
        goto fail;
3171

    
3172
    c->fd = -1;
3173
    c->poll_entry = NULL;
3174
    c->from_addr = *from_addr;
3175
    c->buffer_size = IOBUFFER_INIT_SIZE;
3176
    c->buffer = av_malloc(c->buffer_size);
3177
    if (!c->buffer)
3178
        goto fail;
3179
    nb_connections++;
3180
    c->stream = stream;
3181
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3182
    c->state = HTTPSTATE_READY;
3183
    c->is_packetized = 1;
3184
    c->rtp_protocol = rtp_protocol;
3185

    
3186
    /* protocol is shown in statistics */
3187
    switch(c->rtp_protocol) {
3188
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3189
        proto_str = "MCAST";
3190
        break;
3191
    case RTSP_LOWER_TRANSPORT_UDP:
3192
        proto_str = "UDP";
3193
        break;
3194
    case RTSP_LOWER_TRANSPORT_TCP:
3195
        proto_str = "TCP";
3196
        break;
3197
    default:
3198
        proto_str = "???";
3199
        break;
3200
    }
3201
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3202
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3203

    
3204
    current_bandwidth += stream->bandwidth;
3205

    
3206
    c->next = first_http_ctx;
3207
    first_http_ctx = c;
3208
    return c;
3209

    
3210
 fail:
3211
    if (c) {
3212
        av_free(c->buffer);
3213
        av_free(c);
3214
    }
3215
    return NULL;
3216
}
3217

    
3218
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3219
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3220
   used. */
3221
static int rtp_new_av_stream(HTTPContext *c,
3222
                             int stream_index, struct sockaddr_in *dest_addr,
3223
                             HTTPContext *rtsp_c)
3224
{
3225
    AVFormatContext *ctx;
3226
    AVStream *st;
3227
    char *ipaddr;
3228
    URLContext *h = NULL;
3229
    uint8_t *dummy_buf;
3230
    int max_packet_size;
3231

    
3232
    /* now we can open the relevant output stream */
3233
    ctx = avformat_alloc_context();
3234
    if (!ctx)
3235
        return -1;
3236
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3237

    
3238
    st = av_mallocz(sizeof(AVStream));
3239
    if (!st)
3240
        goto fail;
3241
    st->codec= avcodec_alloc_context();
3242
    ctx->nb_streams = 1;
3243
    ctx->streams[0] = st;
3244

    
3245
    if (!c->stream->feed ||
3246
        c->stream->feed == c->stream)
3247
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3248
    else
3249
        memcpy(st,
3250
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3251
               sizeof(AVStream));
3252
    st->priv_data = NULL;
3253

    
3254
    /* build destination RTP address */
3255
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3256

    
3257
    switch(c->rtp_protocol) {
3258
    case RTSP_LOWER_TRANSPORT_UDP:
3259
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3260
        /* RTP/UDP case */
3261

    
3262
        /* XXX: also pass as parameter to function ? */
3263
        if (c->stream->is_multicast) {
3264
            int ttl;
3265
            ttl = c->stream->multicast_ttl;
3266
            if (!ttl)
3267
                ttl = 16;
3268
            snprintf(ctx->filename, sizeof(ctx->filename),
3269
                     "rtp://%s:%d?multicast=1&ttl=%d",
3270
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3271
        } else {
3272
            snprintf(ctx->filename, sizeof(ctx->filename),
3273
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3274
        }
3275

    
3276
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3277
            goto fail;
3278
        c->rtp_handles[stream_index] = h;
3279
        max_packet_size = url_get_max_packet_size(h);
3280
        break;
3281
    case RTSP_LOWER_TRANSPORT_TCP:
3282
        /* RTP/TCP case */
3283
        c->rtsp_c = rtsp_c;
3284
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3285
        break;
3286
    default:
3287
        goto fail;
3288
    }
3289

    
3290
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3291
             ipaddr, ntohs(dest_addr->sin_port),
3292
             c->stream->filename, stream_index, c->protocol);
3293

    
3294
    /* normally, no packets should be output here, but the packet size may be checked */
3295
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3296
        /* XXX: close stream */
3297
        goto fail;
3298
    }
3299
    av_set_parameters(ctx, NULL);
3300
    if (av_write_header(ctx) < 0) {
3301
    fail:
3302
        if (h)
3303
            url_close(h);
3304
        av_free(ctx);
3305
        return -1;
3306
    }
3307
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3308
    av_free(dummy_buf);
3309

    
3310
    c->rtp_ctx[stream_index] = ctx;
3311
    return 0;
3312
}
3313

    
3314
/********************************************************************/
3315
/* ffserver initialization */
3316

    
3317
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3318
{
3319
    AVStream *fst;
3320

    
3321
    fst = av_mallocz(sizeof(AVStream));
3322
    if (!fst)
3323
        return NULL;
3324
    fst->codec= avcodec_alloc_context();
3325
    fst->priv_data = av_mallocz(sizeof(FeedData));
3326
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3327
    fst->index = stream->nb_streams;
3328
    av_set_pts_info(fst, 33, 1, 90000);
3329
    stream->streams[stream->nb_streams++] = fst;
3330
    return fst;
3331
}
3332

    
3333
/* return the stream number in the feed */
3334
static int add_av_stream(FFStream *feed, AVStream *st)
3335
{
3336
    AVStream *fst;
3337
    AVCodecContext *av, *av1;
3338
    int i;
3339

    
3340
    av = st->codec;
3341
    for(i=0;i<feed->nb_streams;i++) {
3342
        st = feed->streams[i];
3343
        av1 = st->codec;
3344
        if (av1->codec_id == av->codec_id &&
3345
            av1->codec_type == av->codec_type &&
3346
            av1->bit_rate == av->bit_rate) {
3347

    
3348
            switch(av->codec_type) {
3349
            case AVMEDIA_TYPE_AUDIO:
3350
                if (av1->channels == av->channels &&
3351
                    av1->sample_rate == av->sample_rate)
3352
                    goto found;
3353
                break;
3354
            case AVMEDIA_TYPE_VIDEO:
3355
                if (av1->width == av->width &&
3356
                    av1->height == av->height &&
3357
                    av1->time_base.den == av->time_base.den &&
3358
                    av1->time_base.num == av->time_base.num &&
3359
                    av1->gop_size == av->gop_size)
3360
                    goto found;
3361
                break;
3362
            default:
3363
                abort();
3364
            }
3365
        }
3366
    }
3367

    
3368
    fst = add_av_stream1(feed, av);
3369
    if (!fst)
3370
        return -1;
3371
    return feed->nb_streams - 1;
3372
 found:
3373
    return i;
3374
}
3375

    
3376
static void remove_stream(FFStream *stream)
3377
{
3378
    FFStream **ps;
3379
    ps = &first_stream;
3380
    while (*ps != NULL) {
3381
        if (*ps == stream)
3382
            *ps = (*ps)->next;
3383
        else
3384
            ps = &(*ps)->next;
3385
    }
3386
}
3387

    
3388
/* specific mpeg4 handling : we extract the raw parameters */
3389
static void extract_mpeg4_header(AVFormatContext *infile)
3390
{
3391
    int mpeg4_count, i, size;
3392
    AVPacket pkt;
3393
    AVStream *st;
3394
    const uint8_t *p;
3395

    
3396
    mpeg4_count = 0;
3397
    for(i=0;i<infile->nb_streams;i++) {
3398
        st = infile->streams[i];
3399
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3400
            st->codec->extradata_size == 0) {
3401
            mpeg4_count++;
3402
        }
3403
    }
3404
    if (!mpeg4_count)
3405
        return;
3406

    
3407
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3408
    while (mpeg4_count > 0) {
3409
        if (av_read_packet(infile, &pkt) < 0)
3410
            break;
3411
        st = infile->streams[pkt.stream_index];
3412
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3413
            st->codec->extradata_size == 0) {
3414
            av_freep(&st->codec->extradata);
3415
            /* fill extradata with the header */
3416
            /* XXX: we make hard suppositions here ! */
3417
            p = pkt.data;
3418
            while (p < pkt.data + pkt.size - 4) {
3419
                /* stop when vop header is found */
3420
                if (p[0] == 0x00 && p[1] == 0x00 &&
3421
                    p[2] == 0x01 && p[3] == 0xb6) {
3422
                    size = p - pkt.data;
3423
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3424
                    st->codec->extradata = av_malloc(size);
3425
                    st->codec->extradata_size = size;
3426
                    memcpy(st->codec->extradata, pkt.data, size);
3427
                    break;
3428
                }
3429
                p++;
3430
            }
3431
            mpeg4_count--;
3432
        }
3433
        av_free_packet(&pkt);
3434
    }
3435
}
3436

    
3437
/* compute the needed AVStream for each file */
3438
static void build_file_streams(void)
3439
{
3440
    FFStream *stream, *stream_next;
3441
    AVFormatContext *infile;
3442
    int i, ret;
3443

    
3444
    /* gather all streams */
3445
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3446
        stream_next = stream->next;
3447
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3448
            !stream->feed) {
3449
            /* the stream comes from a file */
3450
            /* try to open the file */
3451
            /* open stream */
3452
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3453
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3454
                /* specific case : if transport stream output to RTP,
3455
                   we use a raw transport stream reader */
3456
                stream->ap_in->mpeg2ts_raw = 1;
3457
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3458
            }
3459

    
3460
            http_log("Opening file '%s'\n", stream->feed_filename);
3461
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3462
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3463
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3464
                /* remove stream (no need to spend more time on it) */
3465
            fail:
3466
                remove_stream(stream);
3467
            } else {
3468
                /* find all the AVStreams inside and reference them in
3469
                   'stream' */
3470
                if (av_find_stream_info(infile) < 0) {
3471
                    http_log("Could not find codec parameters from '%s'\n",
3472
                             stream->feed_filename);
3473
                    av_close_input_file(infile);
3474
                    goto fail;
3475
                }
3476
                extract_mpeg4_header(infile);
3477

    
3478
                for(i=0;i<infile->nb_streams;i++)
3479
                    add_av_stream1(stream, infile->streams[i]->codec);
3480

    
3481
                av_close_input_file(infile);
3482
            }
3483
        }
3484
    }
3485
}
3486

    
3487
/* compute the needed AVStream for each feed */
3488
static void build_feed_streams(void)
3489
{
3490
    FFStream *stream, *feed;
3491
    int i;
3492

    
3493
    /* gather all streams */
3494
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3495
        feed = stream->feed;
3496
        if (feed) {
3497
            if (!stream->is_feed) {
3498
                /* we handle a stream coming from a feed */
3499
                for(i=0;i<stream->nb_streams;i++)
3500
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3501
            }
3502
        }
3503
    }
3504

    
3505
    /* gather all streams */
3506
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3507
        feed = stream->feed;
3508
        if (feed) {
3509
            if (stream->is_feed) {
3510
                for(i=0;i<stream->nb_streams;i++)
3511
                    stream->feed_streams[i] = i;
3512
            }
3513
        }
3514
    }
3515

    
3516
    /* create feed files if needed */
3517
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3518
        int fd;
3519

    
3520
        if (url_exist(feed->feed_filename)) {
3521
            /* See if it matches */
3522
            AVFormatContext *s;
3523
            int matches = 0;
3524

    
3525
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3526
                /* Now see if it matches */
3527
                if (s->nb_streams == feed->nb_streams) {
3528
                    matches = 1;
3529
                    for(i=0;i<s->nb_streams;i++) {
3530
                        AVStream *sf, *ss;
3531
                        sf = feed->streams[i];
3532
                        ss = s->streams[i];
3533

    
3534
                        if (sf->index != ss->index ||
3535
                            sf->id != ss->id) {
3536
                            http_log("Index & Id do not match for stream %d (%s)\n",
3537
                                   i, feed->feed_filename);
3538
                            matches = 0;
3539
                        } else {
3540
                            AVCodecContext *ccf, *ccs;
3541

    
3542
                            ccf = sf->codec;
3543
                            ccs = ss->codec;
3544
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3545

    
3546
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3547
                                http_log("Codecs do not match for stream %d\n", i);
3548
                                matches = 0;
3549
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3550
                                http_log("Codec bitrates do not match for stream %d\n", i);
3551
                                matches = 0;
3552
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3553
                                if (CHECK_CODEC(time_base.den) ||
3554
                                    CHECK_CODEC(time_base.num) ||
3555
                                    CHECK_CODEC(width) ||
3556
                                    CHECK_CODEC(height)) {
3557
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3558
                                    matches = 0;
3559
                                }
3560
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3561
                                if (CHECK_CODEC(sample_rate) ||
3562
                                    CHECK_CODEC(channels) ||
3563
                                    CHECK_CODEC(frame_size)) {
3564
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3565
                                    matches = 0;
3566
                                }
3567
                            } else {
3568
                                http_log("Unknown codec type\n");
3569
                                matches = 0;
3570
                            }
3571
                        }
3572
                        if (!matches)
3573
                            break;
3574
                    }
3575
                } else
3576
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3577
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3578

    
3579
                av_close_input_file(s);
3580
            } else
3581
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3582
                        feed->feed_filename);
3583

    
3584
            if (!matches) {
3585
                if (feed->readonly) {
3586
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3587
                        feed->feed_filename);
3588
                    exit(1);
3589
                }
3590
                unlink(feed->feed_filename);
3591
            }
3592
        }
3593
        if (!url_exist(feed->feed_filename)) {
3594
            AVFormatContext s1 = {0}, *s = &s1;
3595

    
3596
            if (feed->readonly) {
3597
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3598
                    feed->feed_filename);
3599
                exit(1);
3600
            }
3601

    
3602
            /* only write the header of the ffm file */
3603
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3604
                http_log("Could not open output feed file '%s'\n",
3605
                         feed->feed_filename);
3606
                exit(1);
3607
            }
3608
            s->oformat = feed->fmt;
3609
            s->nb_streams = feed->nb_streams;
3610
            for(i=0;i<s->nb_streams;i++) {
3611
                AVStream *st;
3612
                st = feed->streams[i];
3613
                s->streams[i] = st;
3614
            }
3615
            av_set_parameters(s, NULL);
3616
            if (av_write_header(s) < 0) {
3617
                http_log("Container doesn't supports the required parameters\n");
3618
                exit(1);
3619
            }
3620
            /* XXX: need better api */
3621
            av_freep(&s->priv_data);
3622
            url_fclose(s->pb);
3623
        }
3624
        /* get feed size and write index */
3625
        fd = open(feed->feed_filename, O_RDONLY);
3626
        if (fd < 0) {
3627
            http_log("Could not open output feed file '%s'\n",
3628
                    feed->feed_filename);
3629
            exit(1);
3630
        }
3631

    
3632
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3633
        feed->feed_size = lseek(fd, 0, SEEK_END);
3634
        /* ensure that we do not wrap before the end of file */
3635
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3636
            feed->feed_max_size = feed->feed_size;
3637

    
3638
        close(fd);
3639
    }
3640
}
3641

    
3642
/* compute the bandwidth used by each stream */
3643
static void compute_bandwidth(void)
3644
{
3645
    unsigned bandwidth;
3646
    int i;
3647
    FFStream *stream;
3648

    
3649
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3650
        bandwidth = 0;
3651
        for(i=0;i<stream->nb_streams;i++) {
3652
            AVStream *st = stream->streams[i];
3653
            switch(st->codec->codec_type) {
3654
            case AVMEDIA_TYPE_AUDIO:
3655
            case AVMEDIA_TYPE_VIDEO:
3656
                bandwidth += st->codec->bit_rate;
3657
                break;
3658
            default:
3659
                break;
3660
            }
3661
        }
3662
        stream->bandwidth = (bandwidth + 999) / 1000;
3663
    }
3664
}
3665

    
3666
/* add a codec and set the default parameters */
3667
static void add_codec(FFStream *stream, AVCodecContext *av)
3668
{
3669
    AVStream *st;
3670

    
3671
    /* compute default parameters */
3672
    switch(av->codec_type) {
3673
    case AVMEDIA_TYPE_AUDIO:
3674
        if (av->bit_rate == 0)
3675
            av->bit_rate = 64000;
3676
        if (av->sample_rate == 0)
3677
            av->sample_rate = 22050;
3678
        if (av->channels == 0)
3679
            av->channels = 1;
3680
        break;
3681
    case AVMEDIA_TYPE_VIDEO:
3682
        if (av->bit_rate == 0)
3683
            av->bit_rate = 64000;
3684
        if (av->time_base.num == 0){
3685
            av->time_base.den = 5;
3686
            av->time_base.num = 1;
3687
        }
3688
        if (av->width == 0 || av->height == 0) {
3689
            av->width = 160;
3690
            av->height = 128;
3691
        }
3692
        /* Bitrate tolerance is less for streaming */
3693
        if (av->bit_rate_tolerance == 0)
3694
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3695
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3696
        if (av->qmin == 0)
3697
            av->qmin = 3;
3698
        if (av->qmax == 0)
3699
            av->qmax = 31;
3700
        if (av->max_qdiff == 0)
3701
            av->max_qdiff = 3;
3702
        av->qcompress = 0.5;
3703
        av->qblur = 0.5;
3704

    
3705
        if (!av->nsse_weight)
3706
            av->nsse_weight = 8;
3707

    
3708
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3709
        av->me_method = ME_EPZS;
3710
        av->rc_buffer_aggressivity = 1.0;
3711

    
3712
        if (!av->rc_eq)
3713
            av->rc_eq = "tex^qComp";
3714
        if (!av->i_quant_factor)
3715
            av->i_quant_factor = -0.8;
3716
        if (!av->b_quant_factor)
3717
            av->b_quant_factor = 1.25;
3718
        if (!av->b_quant_offset)
3719
            av->b_quant_offset = 1.25;
3720
        if (!av->rc_max_rate)
3721
            av->rc_max_rate = av->bit_rate * 2;
3722

    
3723
        if (av->rc_max_rate && !av->rc_buffer_size) {
3724
            av->rc_buffer_size = av->rc_max_rate;
3725
        }
3726

    
3727

    
3728
        break;
3729
    default:
3730
        abort();
3731
    }
3732

    
3733
    st = av_mallocz(sizeof(AVStream));
3734
    if (!st)
3735
        return;
3736
    st->codec = avcodec_alloc_context();
3737
    stream->streams[stream->nb_streams++] = st;
3738
    memcpy(st->codec, av, sizeof(AVCodecContext));
3739
}
3740

    
3741
static enum CodecID opt_audio_codec(const char *arg)
3742
{
3743
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3744

    
3745
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3746
        return CODEC_ID_NONE;
3747

    
3748
    return p->id;
3749
}
3750

    
3751
static enum CodecID opt_video_codec(const char *arg)
3752
{
3753
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3754

    
3755
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3756
        return CODEC_ID_NONE;
3757

    
3758
    return p->id;
3759
}
3760

    
3761
/* simplistic plugin support */
3762

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

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

    
3783
    init_func();
3784
}
3785
#endif
3786

    
3787
static int ffserver_opt_default(const char *opt, const char *arg,
3788
                       AVCodecContext *avctx, int type)
3789
{
3790
    int ret = 0;
3791
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3792
    if(o)
3793
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3794
    return ret;
3795
}
3796

    
3797
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3798
                                             const char *mime_type)
3799
{
3800
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3801

    
3802
    if (fmt) {
3803
        AVOutputFormat *stream_fmt;
3804
        char stream_format_name[64];
3805

    
3806
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3807
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3808

    
3809
        if (stream_fmt)
3810
            fmt = stream_fmt;
3811
    }
3812

    
3813
    return fmt;
3814
}
3815

    
3816
static int parse_ffconfig(const char *filename)
3817
{
3818
    FILE *f;
3819
    char line[1024];
3820
    char cmd[64];
3821
    char arg[1024];
3822
    const char *p;
3823
    int val, errors, line_num;
3824
    FFStream **last_stream, *stream, *redirect;
3825
    FFStream **last_feed, *feed, *s;
3826
    AVCodecContext audio_enc, video_enc;
3827
    enum CodecID audio_id, video_id;
3828

    
3829
    f = fopen(filename, "r");
3830
    if (!f) {
3831
        perror(filename);
3832
        return -1;
3833
    }
3834

    
3835
    errors = 0;
3836
    line_num = 0;
3837
    first_stream = NULL;
3838
    last_stream = &first_stream;
3839
    first_feed = NULL;
3840
    last_feed = &first_feed;
3841
    stream = NULL;
3842
    feed = NULL;
3843
    redirect = NULL;
3844
    audio_id = CODEC_ID_NONE;
3845
    video_id = CODEC_ID_NONE;
3846
    for(;;) {
3847
        if (fgets(line, sizeof(line), f) == NULL)
3848
            break;
3849
        line_num++;
3850
        p = line;
3851
        while (isspace(*p))
3852
            p++;
3853
        if (*p == '\0' || *p == '#')
3854
            continue;
3855

    
3856
        get_arg(cmd, sizeof(cmd), &p);
3857

    
3858
        if (!strcasecmp(cmd, "Port")) {
3859
            get_arg(arg, sizeof(arg), &p);
3860
            val = atoi(arg);
3861
            if (val < 1 || val > 65536) {
3862
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3863
                        filename, line_num, arg);
3864
                errors++;
3865
            }
3866
            my_http_addr.sin_port = htons(val);
3867
        } else if (!strcasecmp(cmd, "BindAddress")) {
3868
            get_arg(arg, sizeof(arg), &p);
3869
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3870
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3871
                        filename, line_num, arg);
3872
                errors++;
3873
            }
3874
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3875
            ffserver_daemon = 0;
3876
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3877
            get_arg(arg, sizeof(arg), &p);
3878
            val = atoi(arg);
3879
            if (val < 1 || val > 65536) {
3880
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3881
                        filename, line_num, arg);
3882
                errors++;
3883
            }
3884
            my_rtsp_addr.sin_port = htons(atoi(arg));
3885
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3886
            get_arg(arg, sizeof(arg), &p);
3887
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3888
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3889
                        filename, line_num, arg);
3890
                errors++;
3891
            }
3892
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3893
            get_arg(arg, sizeof(arg), &p);
3894
            val = atoi(arg);
3895
            if (val < 1 || val > 65536) {
3896
                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3897
                        filename, line_num, arg);
3898
                errors++;
3899
            }
3900
            nb_max_http_connections = val;
3901
        } else if (!strcasecmp(cmd, "MaxClients")) {
3902
            get_arg(arg, sizeof(arg), &p);
3903
            val = atoi(arg);
3904
            if (val < 1 || val > nb_max_http_connections) {
3905
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3906
                        filename, line_num, arg);
3907
                errors++;
3908
            } else {
3909
                nb_max_connections = val;
3910
            }
3911
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3912
            int64_t llval;
3913
            get_arg(arg, sizeof(arg), &p);
3914
            llval = atoll(arg);
3915
            if (llval < 10 || llval > 10000000) {
3916
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3917
                        filename, line_num, arg);
3918
                errors++;
3919
            } else
3920
                max_bandwidth = llval;
3921
        } else if (!strcasecmp(cmd, "CustomLog")) {
3922
            if (!ffserver_debug)
3923
                get_arg(logfilename, sizeof(logfilename), &p);
3924
        } else if (!strcasecmp(cmd, "<Feed")) {
3925
            /*********************************************/
3926
            /* Feed related options */
3927
            char *q;
3928
            if (stream || feed) {
3929
                fprintf(stderr, "%s:%d: Already in a tag\n",
3930
                        filename, line_num);
3931
            } else {
3932
                feed = av_mallocz(sizeof(FFStream));
3933
                get_arg(feed->filename, sizeof(feed->filename), &p);
3934
                q = strrchr(feed->filename, '>');
3935
                if (*q)
3936
                    *q = '\0';
3937

    
3938
                for (s = first_feed; s; s = s->next) {
3939
                    if (!strcmp(feed->filename, s->filename)) {
3940
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3941
                                filename, line_num, s->filename);
3942
                        errors++;
3943
                    }
3944
                }
3945

    
3946
                feed->fmt = av_guess_format("ffm", NULL, NULL);
3947
                /* defaut feed file */
3948
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3949
                         "/tmp/%s.ffm", feed->filename);
3950
                feed->feed_max_size = 5 * 1024 * 1024;
3951
                feed->is_feed = 1;
3952
                feed->feed = feed; /* self feeding :-) */
3953

    
3954
                /* add in stream list */
3955
                *last_stream = feed;
3956
                last_stream = &feed->next;
3957
                /* add in feed list */
3958
                *last_feed = feed;
3959
                last_feed = &feed->next_feed;
3960
            }
3961
        } else if (!strcasecmp(cmd, "Launch")) {
3962
            if (feed) {
3963
                int i;
3964

    
3965
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3966

    
3967
                for (i = 0; i < 62; i++) {
3968
                    get_arg(arg, sizeof(arg), &p);
3969
                    if (!arg[0])
3970
                        break;
3971

    
3972
                    feed->child_argv[i] = av_strdup(arg);
3973
                }
3974

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

    
3977
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3978
                    "http://%s:%d/%s",
3979
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3980
                    inet_ntoa(my_http_addr.sin_addr),
3981
                    ntohs(my_http_addr.sin_port), feed->filename);
3982
            }
3983
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3984
            if (feed) {
3985
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3986
                feed->readonly = 1;
3987
            } else if (stream) {
3988
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3989
            }
3990
        } else if (!strcasecmp(cmd, "File")) {
3991
            if (feed) {
3992
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3993
            } else if (stream)
3994
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3995
        } else if (!strcasecmp(cmd, "Truncate")) {
3996
            if (feed) {
3997
                get_arg(arg, sizeof(arg), &p);
3998
                feed->truncate = strtod(arg, NULL);
3999
            }
4000
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4001
            if (feed) {
4002
                char *p1;
4003
                double fsize;
4004

    
4005
                get_arg(arg, sizeof(arg), &p);
4006
                p1 = arg;
4007
                fsize = strtod(p1, &p1);
4008
                switch(toupper(*p1)) {
4009
                case 'K':
4010
                    fsize *= 1024;
4011
                    break;
4012
                case 'M':
4013
                    fsize *= 1024 * 1024;
4014
                    break;
4015
                case 'G':
4016
                    fsize *= 1024 * 1024 * 1024;
4017
                    break;
4018
                }
4019
                feed->feed_max_size = (int64_t)fsize;
4020
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4021
                    fprintf(stderr, "%s:%d: Feed max file size is too small, "
4022
                            "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
4023
                    errors++;
4024
                }
4025
            }
4026
        } else if (!strcasecmp(cmd, "</Feed>")) {
4027
            if (!feed) {
4028
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
4029
                        filename, line_num);
4030
                errors++;
4031
            }
4032
            feed = NULL;
4033
        } else if (!strcasecmp(cmd, "<Stream")) {
4034
            /*********************************************/
4035
            /* Stream related options */
4036
            char *q;
4037
            if (stream || feed) {
4038
                fprintf(stderr, "%s:%d: Already in a tag\n",
4039
                        filename, line_num);
4040
            } else {
4041
                FFStream *s;
4042
                const AVClass *class;
4043
                stream = av_mallocz(sizeof(FFStream));
4044
                get_arg(stream->filename, sizeof(stream->filename), &p);
4045
                q = strrchr(stream->filename, '>');
4046
                if (*q)
4047
                    *q = '\0';
4048

    
4049
                for (s = first_stream; s; s = s->next) {
4050
                    if (!strcmp(stream->filename, s->filename)) {
4051
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
4052
                                filename, line_num, s->filename);
4053
                        errors++;
4054
                    }
4055
                }
4056

    
4057
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4058
                /* fetch avclass so AVOption works
4059
                 * FIXME try to use avcodec_get_context_defaults2
4060
                 * without changing defaults too much */
4061
                avcodec_get_context_defaults(&video_enc);
4062
                class = video_enc.av_class;
4063
                memset(&audio_enc, 0, sizeof(AVCodecContext));
4064
                memset(&video_enc, 0, sizeof(AVCodecContext));
4065
                audio_enc.av_class = class;
4066
                video_enc.av_class = class;
4067
                audio_id = CODEC_ID_NONE;
4068
                video_id = CODEC_ID_NONE;
4069
                if (stream->fmt) {
4070
                    audio_id = stream->fmt->audio_codec;
4071
                    video_id = stream->fmt->video_codec;
4072
                }
4073

    
4074
                *last_stream = stream;
4075
                last_stream = &stream->next;
4076
            }
4077
        } else if (!strcasecmp(cmd, "Feed")) {
4078
            get_arg(arg, sizeof(arg), &p);
4079
            if (stream) {
4080
                FFStream *sfeed;
4081

    
4082
                sfeed = first_feed;
4083
                while (sfeed != NULL) {
4084
                    if (!strcmp(sfeed->filename, arg))
4085
                        break;
4086
                    sfeed = sfeed->next_feed;
4087
                }
4088
                if (!sfeed)
4089
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4090
                            filename, line_num, arg);
4091
                else
4092
                    stream->feed = sfeed;
4093
            }
4094
        } else if (!strcasecmp(cmd, "Format")) {
4095
            get_arg(arg, sizeof(arg), &p);
4096
            if (stream) {
4097
                if (!strcmp(arg, "status")) {
4098
                    stream->stream_type = STREAM_TYPE_STATUS;
4099
                    stream->fmt = NULL;
4100
                } else {
4101
                    stream->stream_type = STREAM_TYPE_LIVE;
4102
                    /* jpeg cannot be used here, so use single frame jpeg */
4103
                    if (!strcmp(arg, "jpeg"))
4104
                        strcpy(arg, "mjpeg");
4105
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4106
                    if (!stream->fmt) {
4107
                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4108
                                filename, line_num, arg);
4109
                        errors++;
4110
                    }
4111
                }
4112
                if (stream->fmt) {
4113
                    audio_id = stream->fmt->audio_codec;
4114
                    video_id = stream->fmt->video_codec;
4115
                }
4116
            }
4117
        } else if (!strcasecmp(cmd, "InputFormat")) {
4118
            get_arg(arg, sizeof(arg), &p);
4119
            if (stream) {
4120
                stream->ifmt = av_find_input_format(arg);
4121
                if (!stream->ifmt) {
4122
                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4123
                            filename, line_num, arg);
4124
                }
4125
            }
4126
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4127
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4128
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4129
            } else {
4130
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4131
                            filename, line_num);
4132
                errors++;
4133
            }
4134
        } else if (!strcasecmp(cmd, "Author")) {
4135
            if (stream)
4136
                get_arg(stream->author, sizeof(stream->author), &p);
4137
        } else if (!strcasecmp(cmd, "Comment")) {
4138
            if (stream)
4139
                get_arg(stream->comment, sizeof(stream->comment), &p);
4140
        } else if (!strcasecmp(cmd, "Copyright")) {
4141
            if (stream)
4142
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4143
        } else if (!strcasecmp(cmd, "Title")) {
4144
            if (stream)
4145
                get_arg(stream->title, sizeof(stream->title), &p);
4146
        } else if (!strcasecmp(cmd, "Preroll")) {
4147
            get_arg(arg, sizeof(arg), &p);
4148
            if (stream)
4149
                stream->prebuffer = atof(arg) * 1000;
4150
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4151
            if (stream)
4152
                stream->send_on_key = 1;
4153
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4154
            get_arg(arg, sizeof(arg), &p);
4155
            audio_id = opt_audio_codec(arg);
4156
            if (audio_id == CODEC_ID_NONE) {
4157
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4158
                        filename, line_num, arg);
4159
                errors++;
4160
            }
4161
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4162
            get_arg(arg, sizeof(arg), &p);
4163
            video_id = opt_video_codec(arg);
4164
            if (video_id == CODEC_ID_NONE) {
4165
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4166
                        filename, line_num, arg);
4167
                errors++;
4168
            }
4169
        } else if (!strcasecmp(cmd, "MaxTime")) {
4170
            get_arg(arg, sizeof(arg), &p);
4171
            if (stream)
4172
                stream->max_time = atof(arg) * 1000;
4173
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4174
            get_arg(arg, sizeof(arg), &p);
4175
            if (stream)
4176
                audio_enc.bit_rate = atoi(arg) * 1000;
4177
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4178
            get_arg(arg, sizeof(arg), &p);
4179
            if (stream)
4180
                audio_enc.channels = atoi(arg);
4181
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4182
            get_arg(arg, sizeof(arg), &p);
4183
            if (stream)
4184
                audio_enc.sample_rate = atoi(arg);
4185
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4186
            get_arg(arg, sizeof(arg), &p);
4187
            if (stream) {
4188
//                audio_enc.quality = atof(arg) * 1000;
4189
            }
4190
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4191
            if (stream) {
4192
                int minrate, maxrate;
4193

    
4194
                get_arg(arg, sizeof(arg), &p);
4195

    
4196
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4197
                    video_enc.rc_min_rate = minrate * 1000;
4198
                    video_enc.rc_max_rate = maxrate * 1000;
4199
                } else {
4200
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4201
                            filename, line_num, arg);
4202
                    errors++;
4203
                }
4204
            }
4205
        } else if (!strcasecmp(cmd, "Debug")) {
4206
            if (stream) {
4207
                get_arg(arg, sizeof(arg), &p);
4208
                video_enc.debug = strtol(arg,0,0);
4209
            }
4210
        } else if (!strcasecmp(cmd, "Strict")) {
4211
            if (stream) {
4212
                get_arg(arg, sizeof(arg), &p);
4213
                video_enc.strict_std_compliance = atoi(arg);
4214
            }
4215
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4216
            if (stream) {
4217
                get_arg(arg, sizeof(arg), &p);
4218
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4219
            }
4220
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4221
            if (stream) {
4222
                get_arg(arg, sizeof(arg), &p);
4223
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4224
            }
4225
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4226
            get_arg(arg, sizeof(arg), &p);
4227
            if (stream) {
4228
                video_enc.bit_rate = atoi(arg) * 1000;
4229
            }
4230
        } else if (!strcasecmp(cmd, "VideoSize")) {
4231
            get_arg(arg, sizeof(arg), &p);
4232
            if (stream) {
4233
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4234
                if ((video_enc.width % 16) != 0 ||
4235
                    (video_enc.height % 16) != 0) {
4236
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4237
                            filename, line_num);
4238
                    errors++;
4239
                }
4240
            }
4241
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4242
            get_arg(arg, sizeof(arg), &p);
4243
            if (stream) {
4244
                AVRational frame_rate;
4245
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4246
                    fprintf(stderr, "Incorrect frame rate\n");
4247
                    errors++;
4248
                } else {
4249
                    video_enc.time_base.num = frame_rate.den;
4250
                    video_enc.time_base.den = frame_rate.num;
4251
                }
4252
            }
4253
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4254
            get_arg(arg, sizeof(arg), &p);
4255
            if (stream)
4256
                video_enc.gop_size = atoi(arg);
4257
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4258
            if (stream)
4259
                video_enc.gop_size = 1;
4260
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4261
            if (stream)
4262
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4263
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4264
            if (stream) {
4265
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4266
                video_enc.flags |= CODEC_FLAG_4MV;
4267
            }
4268
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4269
                   !strcasecmp(cmd, "AVOptionAudio")) {
4270
            char arg2[1024];
4271
            AVCodecContext *avctx;
4272
            int type;
4273
            get_arg(arg, sizeof(arg), &p);
4274
            get_arg(arg2, sizeof(arg2), &p);
4275
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4276
                avctx = &video_enc;
4277
                type = AV_OPT_FLAG_VIDEO_PARAM;
4278
            } else {
4279
                avctx = &audio_enc;
4280
                type = AV_OPT_FLAG_AUDIO_PARAM;
4281
            }
4282
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4283
                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4284
                errors++;
4285
            }
4286
        } else if (!strcasecmp(cmd, "VideoTag")) {
4287
            get_arg(arg, sizeof(arg), &p);
4288
            if ((strlen(arg) == 4) && stream)
4289
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4290
        } else if (!strcasecmp(cmd, "BitExact")) {
4291
            if (stream)
4292
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4293
        } else if (!strcasecmp(cmd, "DctFastint")) {
4294
            if (stream)
4295
                video_enc.dct_algo  = FF_DCT_FASTINT;
4296
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4297
            if (stream)
4298
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4299
        } else if (!strcasecmp(cmd, "Qscale")) {
4300
            get_arg(arg, sizeof(arg), &p);
4301
            if (stream) {
4302
                video_enc.flags |= CODEC_FLAG_QSCALE;
4303
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4304
            }
4305
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4306
            get_arg(arg, sizeof(arg), &p);
4307
            if (stream) {
4308
                video_enc.max_qdiff = atoi(arg);
4309
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4310
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4311
                            filename, line_num);
4312
                    errors++;
4313
                }
4314
            }
4315
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4316
            get_arg(arg, sizeof(arg), &p);
4317
            if (stream) {
4318
                video_enc.qmax = atoi(arg);
4319
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4320
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4321
                            filename, line_num);
4322
                    errors++;
4323
                }
4324
            }
4325
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4326
            get_arg(arg, sizeof(arg), &p);
4327
            if (stream) {
4328
                video_enc.qmin = atoi(arg);
4329
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4330
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4331
                            filename, line_num);
4332
                    errors++;
4333
                }
4334
            }
4335
        } else if (!strcasecmp(cmd, "LumaElim")) {
4336
            get_arg(arg, sizeof(arg), &p);
4337
            if (stream)
4338
                video_enc.luma_elim_threshold = atoi(arg);
4339
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4340
            get_arg(arg, sizeof(arg), &p);
4341
            if (stream)
4342
                video_enc.chroma_elim_threshold = atoi(arg);
4343
        } else if (!strcasecmp(cmd, "LumiMask")) {
4344
            get_arg(arg, sizeof(arg), &p);
4345
            if (stream)
4346
                video_enc.lumi_masking = atof(arg);
4347
        } else if (!strcasecmp(cmd, "DarkMask")) {
4348
            get_arg(arg, sizeof(arg), &p);
4349
            if (stream)
4350
                video_enc.dark_masking = atof(arg);
4351
        } else if (!strcasecmp(cmd, "NoVideo")) {
4352
            video_id = CODEC_ID_NONE;
4353
        } else if (!strcasecmp(cmd, "NoAudio")) {
4354
            audio_id = CODEC_ID_NONE;
4355
        } else if (!strcasecmp(cmd, "ACL")) {
4356
            IPAddressACL acl;
4357

    
4358
            get_arg(arg, sizeof(arg), &p);
4359
            if (strcasecmp(arg, "allow") == 0)
4360
                acl.action = IP_ALLOW;
4361
            else if (strcasecmp(arg, "deny") == 0)
4362
                acl.action = IP_DENY;
4363
            else {
4364
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4365
                        filename, line_num, arg);
4366
                errors++;
4367
            }
4368

    
4369
            get_arg(arg, sizeof(arg), &p);
4370

    
4371
            if (resolve_host(&acl.first, arg) != 0) {
4372
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4373
                        filename, line_num, arg);
4374
                errors++;
4375
            } else
4376
                acl.last = acl.first;
4377

    
4378
            get_arg(arg, sizeof(arg), &p);
4379

    
4380
            if (arg[0]) {
4381
                if (resolve_host(&acl.last, arg) != 0) {
4382
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4383
                            filename, line_num, arg);
4384
                    errors++;
4385
                }
4386
            }
4387

    
4388
            if (!errors) {
4389
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4390
                IPAddressACL **naclp = 0;
4391

    
4392
                acl.next = 0;
4393
                *nacl = acl;
4394

    
4395
                if (stream)
4396
                    naclp = &stream->acl;
4397
                else if (feed)
4398
                    naclp = &feed->acl;
4399
                else {
4400
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4401
                            filename, line_num);
4402
                    errors++;
4403
                }
4404

    
4405
                if (naclp) {
4406
                    while (*naclp)
4407
                        naclp = &(*naclp)->next;
4408

    
4409
                    *naclp = nacl;
4410
                }
4411
            }
4412
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4413
            get_arg(arg, sizeof(arg), &p);
4414
            if (stream) {
4415
                av_freep(&stream->rtsp_option);
4416
                stream->rtsp_option = av_strdup(arg);
4417
            }
4418
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4419
            get_arg(arg, sizeof(arg), &p);
4420
            if (stream) {
4421
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4422
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4423
                            filename, line_num, arg);
4424
                    errors++;
4425
                }
4426
                stream->is_multicast = 1;
4427
                stream->loop = 1; /* default is looping */
4428
            }
4429
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4430
            get_arg(arg, sizeof(arg), &p);
4431
            if (stream)
4432
                stream->multicast_port = atoi(arg);
4433
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4434
            get_arg(arg, sizeof(arg), &p);
4435
            if (stream)
4436
                stream->multicast_ttl = atoi(arg);
4437
        } else if (!strcasecmp(cmd, "NoLoop")) {
4438
            if (stream)
4439
                stream->loop = 0;
4440
        } else if (!strcasecmp(cmd, "</Stream>")) {
4441
            if (!stream) {
4442
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4443
                        filename, line_num);
4444
                errors++;
4445
            } else {
4446
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4447
                    if (audio_id != CODEC_ID_NONE) {
4448
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4449
                        audio_enc.codec_id = audio_id;
4450
                        add_codec(stream, &audio_enc);
4451
                    }
4452
                    if (video_id != CODEC_ID_NONE) {
4453
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4454
                        video_enc.codec_id = video_id;
4455
                        add_codec(stream, &video_enc);
4456
                    }
4457
                }
4458
                stream = NULL;
4459
            }
4460
        } else if (!strcasecmp(cmd, "<Redirect")) {
4461
            /*********************************************/
4462
            char *q;
4463
            if (stream || feed || redirect) {
4464
                fprintf(stderr, "%s:%d: Already in a tag\n",
4465
                        filename, line_num);
4466
                errors++;
4467
            } else {
4468
                redirect = av_mallocz(sizeof(FFStream));
4469
                *last_stream = redirect;
4470
                last_stream = &redirect->next;
4471

    
4472
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4473
                q = strrchr(redirect->filename, '>');
4474
                if (*q)
4475
                    *q = '\0';
4476
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4477
            }
4478
        } else if (!strcasecmp(cmd, "URL")) {
4479
            if (redirect)
4480
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4481
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4482
            if (!redirect) {
4483
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4484
                        filename, line_num);
4485
                errors++;
4486
            } else {
4487
                if (!redirect->feed_filename[0]) {
4488
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4489
                            filename, line_num);
4490
                    errors++;
4491
                }
4492
                redirect = NULL;
4493
            }
4494
        } else if (!strcasecmp(cmd, "LoadModule")) {
4495
            get_arg(arg, sizeof(arg), &p);
4496
#if HAVE_DLOPEN
4497
            load_module(arg);
4498
#else
4499
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4500
                    filename, line_num, arg);
4501
            errors++;
4502
#endif
4503
        } else {
4504
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4505
                    filename, line_num, cmd);
4506
        }
4507
    }
4508

    
4509
    fclose(f);
4510
    if (errors)
4511
        return -1;
4512
    else
4513
        return 0;
4514
}
4515

    
4516
static void handle_child_exit(int sig)
4517
{
4518
    pid_t pid;
4519
    int status;
4520

    
4521
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4522
        FFStream *feed;
4523

    
4524
        for (feed = first_feed; feed; feed = feed->next) {
4525
            if (feed->pid == pid) {
4526
                int uptime = time(0) - feed->pid_start;
4527

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

    
4531
                if (uptime < 30)
4532
                    /* Turn off any more restarts */
4533
                    feed->child_argv = 0;
4534
            }
4535
        }
4536
    }
4537

    
4538
    need_to_start_children = 1;
4539
}
4540

    
4541
static void opt_debug(void)
4542
{
4543
    ffserver_debug = 1;
4544
    ffserver_daemon = 0;
4545
    logfilename[0] = '-';
4546
}
4547

    
4548
static void show_help(void)
4549
{
4550
    printf("usage: ffserver [options]\n"
4551
           "Hyper fast multi format Audio/Video streaming server\n");
4552
    printf("\n");
4553
    show_help_options(options, "Main options:\n", 0, 0);
4554
}
4555

    
4556
static const OptionDef options[] = {
4557
#include "cmdutils_common_opts.h"
4558
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4559
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4560
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4561
    { NULL },
4562
};
4563

    
4564
int main(int argc, char **argv)
4565
{
4566
    struct sigaction sigact;
4567

    
4568
    av_register_all();
4569

    
4570
    show_banner();
4571

    
4572
    config_filename = "/etc/ffserver.conf";
4573

    
4574
    my_program_name = argv[0];
4575
    my_program_dir = getcwd(0, 0);
4576
    ffserver_daemon = 1;
4577

    
4578
    parse_options(argc, argv, options, NULL);
4579

    
4580
    unsetenv("http_proxy");             /* Kill the http_proxy */
4581

    
4582
    av_lfg_init(&random_state, ff_random_get_seed());
4583

    
4584
    memset(&sigact, 0, sizeof(sigact));
4585
    sigact.sa_handler = handle_child_exit;
4586
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4587
    sigaction(SIGCHLD, &sigact, 0);
4588

    
4589
    if (parse_ffconfig(config_filename) < 0) {
4590
        fprintf(stderr, "Incorrect config file - exiting.\n");
4591
        exit(1);
4592
    }
4593

    
4594
    /* open log file if needed */
4595
    if (logfilename[0] != '\0') {
4596
        if (!strcmp(logfilename, "-"))
4597
            logfile = stdout;
4598
        else
4599
            logfile = fopen(logfilename, "a");
4600
        av_log_set_callback(http_av_log);
4601
    }
4602

    
4603
    build_file_streams();
4604

    
4605
    build_feed_streams();
4606

    
4607
    compute_bandwidth();
4608

    
4609
    /* put the process in background and detach it from its TTY */
4610
    if (ffserver_daemon) {
4611
        int pid;
4612

    
4613
        pid = fork();
4614
        if (pid < 0) {
4615
            perror("fork");
4616
            exit(1);
4617
        } else if (pid > 0) {
4618
            /* parent : exit */
4619
            exit(0);
4620
        } else {
4621
            /* child */
4622
            setsid();
4623
            close(0);
4624
            open("/dev/null", O_RDWR);
4625
            if (strcmp(logfilename, "-") != 0) {
4626
                close(1);
4627
                dup(0);
4628
            }
4629
            close(2);
4630
            dup(0);
4631
        }
4632
    }
4633

    
4634
    /* signal init */
4635
    signal(SIGPIPE, SIG_IGN);
4636

    
4637
    if (ffserver_daemon)
4638
        chdir("/");
4639

    
4640
    if (http_server() < 0) {
4641
        http_log("Could not start server\n");
4642
        exit(1);
4643
    }
4644

    
4645
    return 0;
4646
}