Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 64159a58

History | View | Annotate | Download (152 KB)

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

    
22
#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
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35
#include "libavformat/rtpdec.h"
36
#include "libavformat/rtsp.h"
37
#include "libavutil/avstring.h"
38
#include "libavutil/lfg.h"
39
#include "libavutil/random_seed.h"
40
#include "libavutil/intreadwrite.h"
41
#include "libavcodec/opt.h"
42
#include <stdarg.h>
43
#include <unistd.h>
44
#include <fcntl.h>
45
#include <sys/ioctl.h>
46
#if HAVE_POLL_H
47
#include <poll.h>
48
#endif
49
#include <errno.h>
50
#include <sys/time.h>
51
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
52
#include <time.h>
53
#include <sys/wait.h>
54
#include <signal.h>
55
#if HAVE_DLFCN_H
56
#include <dlfcn.h>
57
#endif
58

    
59
#include "cmdutils.h"
60

    
61
#undef exit
62

    
63
const char program_name[] = "FFserver";
64
const int program_birth_year = 2000;
65

    
66
static const OptionDef options[];
67

    
68
enum HTTPState {
69
    HTTPSTATE_WAIT_REQUEST,
70
    HTTPSTATE_SEND_HEADER,
71
    HTTPSTATE_SEND_DATA_HEADER,
72
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
73
    HTTPSTATE_SEND_DATA_TRAILER,
74
    HTTPSTATE_RECEIVE_DATA,
75
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
76
    HTTPSTATE_READY,
77

    
78
    RTSPSTATE_WAIT_REQUEST,
79
    RTSPSTATE_SEND_REPLY,
80
    RTSPSTATE_SEND_PACKET,
81
};
82

    
83
static const char *http_state[] = {
84
    "HTTP_WAIT_REQUEST",
85
    "HTTP_SEND_HEADER",
86

    
87
    "SEND_DATA_HEADER",
88
    "SEND_DATA",
89
    "SEND_DATA_TRAILER",
90
    "RECEIVE_DATA",
91
    "WAIT_FEED",
92
    "READY",
93

    
94
    "RTSP_WAIT_REQUEST",
95
    "RTSP_SEND_REPLY",
96
    "RTSP_SEND_PACKET",
97
};
98

    
99
#define IOBUFFER_INIT_SIZE 8192
100

    
101
/* timeouts are in ms */
102
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

    
107
typedef struct RTSPActionServerSetup {
108
    uint32_t ipaddr;
109
    char transport_option[512];
110
} RTSPActionServerSetup;
111

    
112
typedef struct {
113
    int64_t count1, count2;
114
    int64_t time1, time2;
115
} DataRateData;
116

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

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

    
167
    /* RTP state specific */
168
    enum RTSPLowerTransport rtp_protocol;
169
    char session_id[32]; /* session id */
170
    AVFormatContext *rtp_ctx[MAX_STREAMS];
171

    
172
    /* RTP/UDP specific */
173
    URLContext *rtp_handles[MAX_STREAMS];
174

    
175
    /* RTP/TCP specific */
176
    struct HTTPContext *rtsp_c;
177
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
178
} HTTPContext;
179

    
180
/* each generated stream is described here */
181
enum StreamType {
182
    STREAM_TYPE_LIVE,
183
    STREAM_TYPE_STATUS,
184
    STREAM_TYPE_REDIRECT,
185
};
186

    
187
enum IPAddressAction {
188
    IP_ALLOW = 1,
189
    IP_DENY,
190
};
191

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

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

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

    
249
typedef struct FeedData {
250
    long long data_count;
251
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
252
} FeedData;
253

    
254
static struct sockaddr_in my_http_addr;
255
static struct sockaddr_in my_rtsp_addr;
256

    
257
static char logfilename[1024];
258
static HTTPContext *first_http_ctx;
259
static FFStream *first_feed;   /* contains only feeds */
260
static FFStream *first_stream; /* contains all streams, including feeds */
261

    
262
static void new_connection(int server_fd, int is_rtsp);
263
static void close_connection(HTTPContext *c);
264

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

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

    
283
/* SDP handling */
284
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
285
                                   struct in_addr my_ip);
286

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

    
295
static const char *my_program_name;
296
static const char *my_program_dir;
297

    
298
static const char *config_filename;
299
static int ffserver_debug;
300
static int ffserver_daemon;
301
static int no_launch;
302
static int need_to_start_children;
303

    
304
/* maximum number of simultaneous HTTP connections */
305
static unsigned int nb_max_http_connections = 2000;
306
static unsigned int nb_max_connections = 5;
307
static unsigned int nb_connections;
308

    
309
static uint64_t max_bandwidth = 1000;
310
static uint64_t current_bandwidth;
311

    
312
static int64_t cur_time;           // Making this global saves on passing it around everywhere
313

    
314
static AVLFG random_state;
315

    
316
static FILE *logfile = NULL;
317

    
318
static char *ctime1(char *buf2)
319
{
320
    time_t ti;
321
    char *p;
322

    
323
    ti = time(NULL);
324
    p = ctime(&ti);
325
    strcpy(buf2, p);
326
    p = buf2 + strlen(p) - 1;
327
    if (*p == '\n')
328
        *p = '\0';
329
    return buf2;
330
}
331

    
332
static void http_vlog(const char *fmt, va_list vargs)
333
{
334
    static int print_prefix = 1;
335
    if (logfile) {
336
        if (print_prefix) {
337
            char buf[32];
338
            ctime1(buf);
339
            fprintf(logfile, "%s ", buf);
340
        }
341
        print_prefix = strstr(fmt, "\n") != NULL;
342
        vfprintf(logfile, fmt, vargs);
343
        fflush(logfile);
344
    }
345
}
346

    
347
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
348
{
349
    va_list vargs;
350
    va_start(vargs, fmt);
351
    http_vlog(fmt, vargs);
352
    va_end(vargs);
353
}
354

    
355
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
356
{
357
    static int print_prefix = 1;
358
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
359
    if (level > av_log_get_level())
360
        return;
361
    if (print_prefix && avc)
362
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
363
    print_prefix = strstr(fmt, "\n") != NULL;
364
    http_vlog(fmt, vargs);
365
}
366

    
367
static void log_connection(HTTPContext *c)
368
{
369
    if (c->suppress_log)
370
        return;
371

    
372
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
373
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
374
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
375
}
376

    
377
static void update_datarate(DataRateData *drd, int64_t count)
378
{
379
    if (!drd->time1 && !drd->count1) {
380
        drd->time1 = drd->time2 = cur_time;
381
        drd->count1 = drd->count2 = count;
382
    } else if (cur_time - drd->time2 > 5000) {
383
        drd->time1 = drd->time2;
384
        drd->count1 = drd->count2;
385
        drd->time2 = cur_time;
386
        drd->count2 = count;
387
    }
388
}
389

    
390
/* In bytes per second */
391
static int compute_datarate(DataRateData *drd, int64_t count)
392
{
393
    if (cur_time == drd->time1)
394
        return 0;
395

    
396
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
397
}
398

    
399

    
400
static void start_children(FFStream *feed)
401
{
402
    if (no_launch)
403
        return;
404

    
405
    for (; feed; feed = feed->next) {
406
        if (feed->child_argv && !feed->pid) {
407
            feed->pid_start = time(0);
408

    
409
            feed->pid = fork();
410

    
411
            if (feed->pid < 0) {
412
                http_log("Unable to create children\n");
413
                exit(1);
414
            }
415
            if (!feed->pid) {
416
                /* In child */
417
                char pathname[1024];
418
                char *slash;
419
                int i;
420

    
421
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
422

    
423
                slash = strrchr(pathname, '/');
424
                if (!slash)
425
                    slash = pathname;
426
                else
427
                    slash++;
428
                strcpy(slash, "ffmpeg");
429

    
430
                http_log("Launch commandline: ");
431
                http_log("%s ", pathname);
432
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
433
                    http_log("%s ", feed->child_argv[i]);
434
                http_log("\n");
435

    
436
                for (i = 3; i < 256; i++)
437
                    close(i);
438

    
439
                if (!ffserver_debug) {
440
                    i = open("/dev/null", O_RDWR);
441
                    if (i != -1) {
442
                        dup2(i, 0);
443
                        dup2(i, 1);
444
                        dup2(i, 2);
445
                        close(i);
446
                    }
447
                }
448

    
449
                /* This is needed to make relative pathnames work */
450
                chdir(my_program_dir);
451

    
452
                signal(SIGPIPE, SIG_DFL);
453

    
454
                execvp(pathname, feed->child_argv);
455

    
456
                _exit(1);
457
            }
458
        }
459
    }
460
}
461

    
462
/* open a listening socket */
463
static int socket_open_listen(struct sockaddr_in *my_addr)
464
{
465
    int server_fd, tmp;
466

    
467
    server_fd = socket(AF_INET,SOCK_STREAM,0);
468
    if (server_fd < 0) {
469
        perror ("socket");
470
        return -1;
471
    }
472

    
473
    tmp = 1;
474
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
475

    
476
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
477
        char bindmsg[32];
478
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
479
        perror (bindmsg);
480
        closesocket(server_fd);
481
        return -1;
482
    }
483

    
484
    if (listen (server_fd, 5) < 0) {
485
        perror ("listen");
486
        closesocket(server_fd);
487
        return -1;
488
    }
489
    ff_socket_nonblock(server_fd, 1);
490

    
491
    return server_fd;
492
}
493

    
494
/* start all multicast streams */
495
static void start_multicast(void)
496
{
497
    FFStream *stream;
498
    char session_id[32];
499
    HTTPContext *rtp_c;
500
    struct sockaddr_in dest_addr;
501
    int default_port, stream_index;
502

    
503
    default_port = 6000;
504
    for(stream = first_stream; stream != NULL; stream = stream->next) {
505
        if (stream->is_multicast) {
506
            /* open the RTP connection */
507
            snprintf(session_id, sizeof(session_id), "%08x%08x",
508
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
509

    
510
            /* choose a port if none given */
511
            if (stream->multicast_port == 0) {
512
                stream->multicast_port = default_port;
513
                default_port += 100;
514
            }
515

    
516
            dest_addr.sin_family = AF_INET;
517
            dest_addr.sin_addr = stream->multicast_ip;
518
            dest_addr.sin_port = htons(stream->multicast_port);
519

    
520
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
522
            if (!rtp_c)
523
                continue;
524

    
525
            if (open_input_stream(rtp_c, "") < 0) {
526
                http_log("Could not open input stream for stream '%s'\n",
527
                         stream->filename);
528
                continue;
529
            }
530

    
531
            /* open each RTP stream */
532
            for(stream_index = 0; stream_index < stream->nb_streams;
533
                stream_index++) {
534
                dest_addr.sin_port = htons(stream->multicast_port +
535
                                           2 * stream_index);
536
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
537
                    http_log("Could not open output stream '%s/streamid=%d'\n",
538
                             stream->filename, stream_index);
539
                    exit(1);
540
                }
541
            }
542

    
543
            /* change state to send data */
544
            rtp_c->state = HTTPSTATE_SEND_DATA;
545
        }
546
    }
547
}
548

    
549
/* main loop of the http server */
550
static int http_server(void)
551
{
552
    int server_fd = 0, rtsp_server_fd = 0;
553
    int ret, delay, delay1;
554
    struct pollfd *poll_table, *poll_entry;
555
    HTTPContext *c, *c_next;
556

    
557
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
558
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
559
        return -1;
560
    }
561

    
562
    if (my_http_addr.sin_port) {
563
        server_fd = socket_open_listen(&my_http_addr);
564
        if (server_fd < 0)
565
            return -1;
566
    }
567

    
568
    if (my_rtsp_addr.sin_port) {
569
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
570
        if (rtsp_server_fd < 0)
571
            return -1;
572
    }
573

    
574
    if (!rtsp_server_fd && !server_fd) {
575
        http_log("HTTP and RTSP disabled.\n");
576
        return -1;
577
    }
578

    
579
    http_log("FFserver started.\n");
580

    
581
    start_children(first_feed);
582

    
583
    start_multicast();
584

    
585
    for(;;) {
586
        poll_entry = poll_table;
587
        if (server_fd) {
588
            poll_entry->fd = server_fd;
589
            poll_entry->events = POLLIN;
590
            poll_entry++;
591
        }
592
        if (rtsp_server_fd) {
593
            poll_entry->fd = rtsp_server_fd;
594
            poll_entry->events = POLLIN;
595
            poll_entry++;
596
        }
597

    
598
        /* wait for events on each HTTP handle */
599
        c = first_http_ctx;
600
        delay = 1000;
601
        while (c != NULL) {
602
            int fd;
603
            fd = c->fd;
604
            switch(c->state) {
605
            case HTTPSTATE_SEND_HEADER:
606
            case RTSPSTATE_SEND_REPLY:
607
            case RTSPSTATE_SEND_PACKET:
608
                c->poll_entry = poll_entry;
609
                poll_entry->fd = fd;
610
                poll_entry->events = POLLOUT;
611
                poll_entry++;
612
                break;
613
            case HTTPSTATE_SEND_DATA_HEADER:
614
            case HTTPSTATE_SEND_DATA:
615
            case HTTPSTATE_SEND_DATA_TRAILER:
616
                if (!c->is_packetized) {
617
                    /* for TCP, we output as much as we can (may need to put a limit) */
618
                    c->poll_entry = poll_entry;
619
                    poll_entry->fd = fd;
620
                    poll_entry->events = POLLOUT;
621
                    poll_entry++;
622
                } else {
623
                    /* when ffserver is doing the timing, we work by
624
                       looking at which packet need to be sent every
625
                       10 ms */
626
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
627
                    if (delay1 < delay)
628
                        delay = delay1;
629
                }
630
                break;
631
            case HTTPSTATE_WAIT_REQUEST:
632
            case HTTPSTATE_RECEIVE_DATA:
633
            case HTTPSTATE_WAIT_FEED:
634
            case RTSPSTATE_WAIT_REQUEST:
635
                /* need to catch errors */
636
                c->poll_entry = poll_entry;
637
                poll_entry->fd = fd;
638
                poll_entry->events = POLLIN;/* Maybe this will work */
639
                poll_entry++;
640
                break;
641
            default:
642
                c->poll_entry = NULL;
643
                break;
644
            }
645
            c = c->next;
646
        }
647

    
648
        /* wait for an event on one connection. We poll at least every
649
           second to handle timeouts */
650
        do {
651
            ret = poll(poll_table, poll_entry - poll_table, delay);
652
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
653
                ff_neterrno() != FF_NETERROR(EINTR))
654
                return -1;
655
        } while (ret < 0);
656

    
657
        cur_time = av_gettime() / 1000;
658

    
659
        if (need_to_start_children) {
660
            need_to_start_children = 0;
661
            start_children(first_feed);
662
        }
663

    
664
        /* now handle the events */
665
        for(c = first_http_ctx; c != NULL; c = c_next) {
666
            c_next = c->next;
667
            if (handle_connection(c) < 0) {
668
                /* close and free the connection */
669
                log_connection(c);
670
                close_connection(c);
671
            }
672
        }
673

    
674
        poll_entry = poll_table;
675
        if (server_fd) {
676
            /* new HTTP connection request ? */
677
            if (poll_entry->revents & POLLIN)
678
                new_connection(server_fd, 0);
679
            poll_entry++;
680
        }
681
        if (rtsp_server_fd) {
682
            /* new RTSP connection request ? */
683
            if (poll_entry->revents & POLLIN)
684
                new_connection(rtsp_server_fd, 1);
685
        }
686
    }
687
}
688

    
689
/* start waiting for a new HTTP/RTSP request */
690
static void start_wait_request(HTTPContext *c, int is_rtsp)
691
{
692
    c->buffer_ptr = c->buffer;
693
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
694

    
695
    if (is_rtsp) {
696
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
697
        c->state = RTSPSTATE_WAIT_REQUEST;
698
    } else {
699
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
700
        c->state = HTTPSTATE_WAIT_REQUEST;
701
    }
702
}
703

    
704
static void http_send_too_busy_reply(int fd)
705
{
706
    char buffer[300];
707
    int len = snprintf(buffer, sizeof(buffer),
708
                       "HTTP/1.0 200 Server too busy\r\n"
709
                       "Content-type: text/html\r\n"
710
                       "\r\n"
711
                       "<html><head><title>Too busy</title></head><body>\r\n"
712
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
713
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
714
                       "</body></html>\r\n",
715
                       nb_connections, nb_max_connections);
716
    send(fd, buffer, len, 0);
717
}
718

    
719

    
720
static void new_connection(int server_fd, int is_rtsp)
721
{
722
    struct sockaddr_in from_addr;
723
    int fd, len;
724
    HTTPContext *c = NULL;
725

    
726
    len = sizeof(from_addr);
727
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
728
                &len);
729
    if (fd < 0) {
730
        http_log("error during accept %s\n", strerror(errno));
731
        return;
732
    }
733
    ff_socket_nonblock(fd, 1);
734

    
735
    if (nb_connections >= nb_max_connections) {
736
        http_send_too_busy_reply(fd);
737
        goto fail;
738
    }
739

    
740
    /* add a new connection */
741
    c = av_mallocz(sizeof(HTTPContext));
742
    if (!c)
743
        goto fail;
744

    
745
    c->fd = fd;
746
    c->poll_entry = NULL;
747
    c->from_addr = from_addr;
748
    c->buffer_size = IOBUFFER_INIT_SIZE;
749
    c->buffer = av_malloc(c->buffer_size);
750
    if (!c->buffer)
751
        goto fail;
752

    
753
    c->next = first_http_ctx;
754
    first_http_ctx = c;
755
    nb_connections++;
756

    
757
    start_wait_request(c, is_rtsp);
758

    
759
    return;
760

    
761
 fail:
762
    if (c) {
763
        av_free(c->buffer);
764
        av_free(c);
765
    }
766
    closesocket(fd);
767
}
768

    
769
static void close_connection(HTTPContext *c)
770
{
771
    HTTPContext **cp, *c1;
772
    int i, nb_streams;
773
    AVFormatContext *ctx;
774
    URLContext *h;
775
    AVStream *st;
776

    
777
    /* remove connection from list */
778
    cp = &first_http_ctx;
779
    while ((*cp) != NULL) {
780
        c1 = *cp;
781
        if (c1 == c)
782
            *cp = c->next;
783
        else
784
            cp = &c1->next;
785
    }
786

    
787
    /* remove references, if any (XXX: do it faster) */
788
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
789
        if (c1->rtsp_c == c)
790
            c1->rtsp_c = NULL;
791
    }
792

    
793
    /* remove connection associated resources */
794
    if (c->fd >= 0)
795
        closesocket(c->fd);
796
    if (c->fmt_in) {
797
        /* close each frame parser */
798
        for(i=0;i<c->fmt_in->nb_streams;i++) {
799
            st = c->fmt_in->streams[i];
800
            if (st->codec->codec)
801
                avcodec_close(st->codec);
802
        }
803
        av_close_input_file(c->fmt_in);
804
    }
805

    
806
    /* free RTP output streams if any */
807
    nb_streams = 0;
808
    if (c->stream)
809
        nb_streams = c->stream->nb_streams;
810

    
811
    for(i=0;i<nb_streams;i++) {
812
        ctx = c->rtp_ctx[i];
813
        if (ctx) {
814
            av_write_trailer(ctx);
815
            av_free(ctx);
816
        }
817
        h = c->rtp_handles[i];
818
        if (h)
819
            url_close(h);
820
    }
821

    
822
    ctx = &c->fmt_ctx;
823

    
824
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
825
        if (ctx->oformat) {
826
            /* prepare header */
827
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
828
                av_write_trailer(ctx);
829
                av_freep(&c->pb_buffer);
830
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
831
            }
832
        }
833
    }
834

    
835
    for(i=0; i<ctx->nb_streams; i++)
836
        av_free(ctx->streams[i]);
837

    
838
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
839
        current_bandwidth -= c->stream->bandwidth;
840

    
841
    /* signal that there is no feed if we are the feeder socket */
842
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
843
        c->stream->feed_opened = 0;
844
        close(c->feed_fd);
845
    }
846

    
847
    av_freep(&c->pb_buffer);
848
    av_freep(&c->packet_buffer);
849
    av_free(c->buffer);
850
    av_free(c);
851
    nb_connections--;
852
}
853

    
854
static int handle_connection(HTTPContext *c)
855
{
856
    int len, ret;
857

    
858
    switch(c->state) {
859
    case HTTPSTATE_WAIT_REQUEST:
860
    case RTSPSTATE_WAIT_REQUEST:
861
        /* timeout ? */
862
        if ((c->timeout - cur_time) < 0)
863
            return -1;
864
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
865
            return -1;
866

    
867
        /* no need to read if no events */
868
        if (!(c->poll_entry->revents & POLLIN))
869
            return 0;
870
        /* read the data */
871
    read_loop:
872
        len = recv(c->fd, c->buffer_ptr, 1, 0);
873
        if (len < 0) {
874
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
875
                ff_neterrno() != FF_NETERROR(EINTR))
876
                return -1;
877
        } else if (len == 0) {
878
            return -1;
879
        } else {
880
            /* search for end of request. */
881
            uint8_t *ptr;
882
            c->buffer_ptr += len;
883
            ptr = c->buffer_ptr;
884
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
885
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
886
                /* request found : parse it and reply */
887
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
888
                    ret = http_parse_request(c);
889
                } else {
890
                    ret = rtsp_parse_request(c);
891
                }
892
                if (ret < 0)
893
                    return -1;
894
            } else if (ptr >= c->buffer_end) {
895
                /* request too long: cannot do anything */
896
                return -1;
897
            } else goto read_loop;
898
        }
899
        break;
900

    
901
    case HTTPSTATE_SEND_HEADER:
902
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
903
            return -1;
904

    
905
        /* no need to write if no events */
906
        if (!(c->poll_entry->revents & POLLOUT))
907
            return 0;
908
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
909
        if (len < 0) {
910
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
911
                ff_neterrno() != FF_NETERROR(EINTR)) {
912
                /* error : close connection */
913
                av_freep(&c->pb_buffer);
914
                return -1;
915
            }
916
        } else {
917
            c->buffer_ptr += len;
918
            if (c->stream)
919
                c->stream->bytes_served += len;
920
            c->data_count += len;
921
            if (c->buffer_ptr >= c->buffer_end) {
922
                av_freep(&c->pb_buffer);
923
                /* if error, exit */
924
                if (c->http_error)
925
                    return -1;
926
                /* all the buffer was sent : synchronize to the incoming stream */
927
                c->state = HTTPSTATE_SEND_DATA_HEADER;
928
                c->buffer_ptr = c->buffer_end = c->buffer;
929
            }
930
        }
931
        break;
932

    
933
    case HTTPSTATE_SEND_DATA:
934
    case HTTPSTATE_SEND_DATA_HEADER:
935
    case HTTPSTATE_SEND_DATA_TRAILER:
936
        /* for packetized output, we consider we can always write (the
937
           input streams sets the speed). It may be better to verify
938
           that we do not rely too much on the kernel queues */
939
        if (!c->is_packetized) {
940
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
941
                return -1;
942

    
943
            /* no need to read if no events */
944
            if (!(c->poll_entry->revents & POLLOUT))
945
                return 0;
946
        }
947
        if (http_send_data(c) < 0)
948
            return -1;
949
        /* close connection if trailer sent */
950
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
951
            return -1;
952
        break;
953
    case HTTPSTATE_RECEIVE_DATA:
954
        /* no need to read if no events */
955
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
956
            return -1;
957
        if (!(c->poll_entry->revents & POLLIN))
958
            return 0;
959
        if (http_receive_data(c) < 0)
960
            return -1;
961
        break;
962
    case HTTPSTATE_WAIT_FEED:
963
        /* no need to read if no events */
964
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
965
            return -1;
966

    
967
        /* nothing to do, we'll be waken up by incoming feed packets */
968
        break;
969

    
970
    case RTSPSTATE_SEND_REPLY:
971
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
972
            av_freep(&c->pb_buffer);
973
            return -1;
974
        }
975
        /* no need to write if no events */
976
        if (!(c->poll_entry->revents & POLLOUT))
977
            return 0;
978
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
979
        if (len < 0) {
980
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
981
                ff_neterrno() != FF_NETERROR(EINTR)) {
982
                /* error : close connection */
983
                av_freep(&c->pb_buffer);
984
                return -1;
985
            }
986
        } else {
987
            c->buffer_ptr += len;
988
            c->data_count += len;
989
            if (c->buffer_ptr >= c->buffer_end) {
990
                /* all the buffer was sent : wait for a new request */
991
                av_freep(&c->pb_buffer);
992
                start_wait_request(c, 1);
993
            }
994
        }
995
        break;
996
    case RTSPSTATE_SEND_PACKET:
997
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
998
            av_freep(&c->packet_buffer);
999
            return -1;
1000
        }
1001
        /* no need to write if no events */
1002
        if (!(c->poll_entry->revents & POLLOUT))
1003
            return 0;
1004
        len = send(c->fd, c->packet_buffer_ptr,
1005
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1006
        if (len < 0) {
1007
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1008
                ff_neterrno() != FF_NETERROR(EINTR)) {
1009
                /* error : close connection */
1010
                av_freep(&c->packet_buffer);
1011
                return -1;
1012
            }
1013
        } else {
1014
            c->packet_buffer_ptr += len;
1015
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1016
                /* all the buffer was sent : wait for a new request */
1017
                av_freep(&c->packet_buffer);
1018
                c->state = RTSPSTATE_WAIT_REQUEST;
1019
            }
1020
        }
1021
        break;
1022
    case HTTPSTATE_READY:
1023
        /* nothing to do */
1024
        break;
1025
    default:
1026
        return -1;
1027
    }
1028
    return 0;
1029
}
1030

    
1031
static int extract_rates(char *rates, int ratelen, const char *request)
1032
{
1033
    const char *p;
1034

    
1035
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1036
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1037
            const char *q = p + 7;
1038

    
1039
            while (*q && *q != '\n' && isspace(*q))
1040
                q++;
1041

    
1042
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1043
                int stream_no;
1044
                int rate_no;
1045

    
1046
                q += 20;
1047

    
1048
                memset(rates, 0xff, ratelen);
1049

    
1050
                while (1) {
1051
                    while (*q && *q != '\n' && *q != ':')
1052
                        q++;
1053

    
1054
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1055
                        break;
1056

    
1057
                    stream_no--;
1058
                    if (stream_no < ratelen && stream_no >= 0)
1059
                        rates[stream_no] = rate_no;
1060

    
1061
                    while (*q && *q != '\n' && !isspace(*q))
1062
                        q++;
1063
                }
1064

    
1065
                return 1;
1066
            }
1067
        }
1068
        p = strchr(p, '\n');
1069
        if (!p)
1070
            break;
1071

    
1072
        p++;
1073
    }
1074

    
1075
    return 0;
1076
}
1077

    
1078
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1079
{
1080
    int i;
1081
    int best_bitrate = 100000000;
1082
    int best = -1;
1083

    
1084
    for (i = 0; i < feed->nb_streams; i++) {
1085
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1086

    
1087
        if (feed_codec->codec_id != codec->codec_id ||
1088
            feed_codec->sample_rate != codec->sample_rate ||
1089
            feed_codec->width != codec->width ||
1090
            feed_codec->height != codec->height)
1091
            continue;
1092

    
1093
        /* Potential stream */
1094

    
1095
        /* We want the fastest stream less than bit_rate, or the slowest
1096
         * faster than bit_rate
1097
         */
1098

    
1099
        if (feed_codec->bit_rate <= bit_rate) {
1100
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1101
                best_bitrate = feed_codec->bit_rate;
1102
                best = i;
1103
            }
1104
        } else {
1105
            if (feed_codec->bit_rate < best_bitrate) {
1106
                best_bitrate = feed_codec->bit_rate;
1107
                best = i;
1108
            }
1109
        }
1110
    }
1111

    
1112
    return best;
1113
}
1114

    
1115
static int modify_current_stream(HTTPContext *c, char *rates)
1116
{
1117
    int i;
1118
    FFStream *req = c->stream;
1119
    int action_required = 0;
1120

    
1121
    /* Not much we can do for a feed */
1122
    if (!req->feed)
1123
        return 0;
1124

    
1125
    for (i = 0; i < req->nb_streams; i++) {
1126
        AVCodecContext *codec = req->streams[i]->codec;
1127

    
1128
        switch(rates[i]) {
1129
            case 0:
1130
                c->switch_feed_streams[i] = req->feed_streams[i];
1131
                break;
1132
            case 1:
1133
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1134
                break;
1135
            case 2:
1136
                /* Wants off or slow */
1137
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1138
#ifdef WANTS_OFF
1139
                /* This doesn't work well when it turns off the only stream! */
1140
                c->switch_feed_streams[i] = -2;
1141
                c->feed_streams[i] = -2;
1142
#endif
1143
                break;
1144
        }
1145

    
1146
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1147
            action_required = 1;
1148
    }
1149

    
1150
    return action_required;
1151
}
1152

    
1153

    
1154
static void do_switch_stream(HTTPContext *c, int i)
1155
{
1156
    if (c->switch_feed_streams[i] >= 0) {
1157
#ifdef PHILIP
1158
        c->feed_streams[i] = c->switch_feed_streams[i];
1159
#endif
1160

    
1161
        /* Now update the stream */
1162
    }
1163
    c->switch_feed_streams[i] = -1;
1164
}
1165

    
1166
/* XXX: factorize in utils.c ? */
1167
/* XXX: take care with different space meaning */
1168
static void skip_spaces(const char **pp)
1169
{
1170
    const char *p;
1171
    p = *pp;
1172
    while (*p == ' ' || *p == '\t')
1173
        p++;
1174
    *pp = p;
1175
}
1176

    
1177
static void get_word(char *buf, int buf_size, const char **pp)
1178
{
1179
    const char *p;
1180
    char *q;
1181

    
1182
    p = *pp;
1183
    skip_spaces(&p);
1184
    q = buf;
1185
    while (!isspace(*p) && *p != '\0') {
1186
        if ((q - buf) < buf_size - 1)
1187
            *q++ = *p;
1188
        p++;
1189
    }
1190
    if (buf_size > 0)
1191
        *q = '\0';
1192
    *pp = p;
1193
}
1194

    
1195
static int validate_acl(FFStream *stream, HTTPContext *c)
1196
{
1197
    enum IPAddressAction last_action = IP_DENY;
1198
    IPAddressACL *acl;
1199
    struct in_addr *src = &c->from_addr.sin_addr;
1200
    unsigned long src_addr = src->s_addr;
1201

    
1202
    for (acl = stream->acl; acl; acl = acl->next) {
1203
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1204
            return (acl->action == IP_ALLOW) ? 1 : 0;
1205
        last_action = acl->action;
1206
    }
1207

    
1208
    /* Nothing matched, so return not the last action */
1209
    return (last_action == IP_DENY) ? 1 : 0;
1210
}
1211

    
1212
/* compute the real filename of a file by matching it without its
1213
   extensions to all the stream filenames */
1214
static void compute_real_filename(char *filename, int max_size)
1215
{
1216
    char file1[1024];
1217
    char file2[1024];
1218
    char *p;
1219
    FFStream *stream;
1220

    
1221
    /* compute filename by matching without the file extensions */
1222
    av_strlcpy(file1, filename, sizeof(file1));
1223
    p = strrchr(file1, '.');
1224
    if (p)
1225
        *p = '\0';
1226
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1227
        av_strlcpy(file2, stream->filename, sizeof(file2));
1228
        p = strrchr(file2, '.');
1229
        if (p)
1230
            *p = '\0';
1231
        if (!strcmp(file1, file2)) {
1232
            av_strlcpy(filename, stream->filename, max_size);
1233
            break;
1234
        }
1235
    }
1236
}
1237

    
1238
enum RedirType {
1239
    REDIR_NONE,
1240
    REDIR_ASX,
1241
    REDIR_RAM,
1242
    REDIR_ASF,
1243
    REDIR_RTSP,
1244
    REDIR_SDP,
1245
};
1246

    
1247
/* parse http request and prepare header */
1248
static int http_parse_request(HTTPContext *c)
1249
{
1250
    char *p;
1251
    enum RedirType redir_type;
1252
    char cmd[32];
1253
    char info[1024], filename[1024];
1254
    char url[1024], *q;
1255
    char protocol[32];
1256
    char msg[1024];
1257
    const char *mime_type;
1258
    FFStream *stream;
1259
    int i;
1260
    char ratebuf[32];
1261
    char *useragent = 0;
1262

    
1263
    p = c->buffer;
1264
    get_word(cmd, sizeof(cmd), (const char **)&p);
1265
    av_strlcpy(c->method, cmd, sizeof(c->method));
1266

    
1267
    if (!strcmp(cmd, "GET"))
1268
        c->post = 0;
1269
    else if (!strcmp(cmd, "POST"))
1270
        c->post = 1;
1271
    else
1272
        return -1;
1273

    
1274
    get_word(url, sizeof(url), (const char **)&p);
1275
    av_strlcpy(c->url, url, sizeof(c->url));
1276

    
1277
    get_word(protocol, sizeof(protocol), (const char **)&p);
1278
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1279
        return -1;
1280

    
1281
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1282

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

    
1286
    /* find the filename and the optional info string in the request */
1287
    p = strchr(url, '?');
1288
    if (p) {
1289
        av_strlcpy(info, p, sizeof(info));
1290
        *p = '\0';
1291
    } else
1292
        info[0] = '\0';
1293

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

    
1296
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1297
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1298
            useragent = p + 11;
1299
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1300
                useragent++;
1301
            break;
1302
        }
1303
        p = strchr(p, '\n');
1304
        if (!p)
1305
            break;
1306

    
1307
        p++;
1308
    }
1309

    
1310
    redir_type = REDIR_NONE;
1311
    if (match_ext(filename, "asx")) {
1312
        redir_type = REDIR_ASX;
1313
        filename[strlen(filename)-1] = 'f';
1314
    } else if (match_ext(filename, "asf") &&
1315
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1316
        /* if this isn't WMP or lookalike, return the redirector file */
1317
        redir_type = REDIR_ASF;
1318
    } else if (match_ext(filename, "rpm,ram")) {
1319
        redir_type = REDIR_RAM;
1320
        strcpy(filename + strlen(filename)-2, "m");
1321
    } else if (match_ext(filename, "rtsp")) {
1322
        redir_type = REDIR_RTSP;
1323
        compute_real_filename(filename, sizeof(filename) - 1);
1324
    } else if (match_ext(filename, "sdp")) {
1325
        redir_type = REDIR_SDP;
1326
        compute_real_filename(filename, sizeof(filename) - 1);
1327
    }
1328

    
1329
    // "redirect" / request to index.html
1330
    if (!strlen(filename))
1331
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1332

    
1333
    stream = first_stream;
1334
    while (stream != NULL) {
1335
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1336
            break;
1337
        stream = stream->next;
1338
    }
1339
    if (stream == NULL) {
1340
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1341
        http_log("File '%s' not found\n", url);
1342
        goto send_error;
1343
    }
1344

    
1345
    c->stream = stream;
1346
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1347
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1348

    
1349
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1350
        c->http_error = 301;
1351
        q = c->buffer;
1352
        q += snprintf(q, c->buffer_size,
1353
                      "HTTP/1.0 301 Moved\r\n"
1354
                      "Location: %s\r\n"
1355
                      "Content-type: text/html\r\n"
1356
                      "\r\n"
1357
                      "<html><head><title>Moved</title></head><body>\r\n"
1358
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1359
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1360
        /* prepare output buffer */
1361
        c->buffer_ptr = c->buffer;
1362
        c->buffer_end = q;
1363
        c->state = HTTPSTATE_SEND_HEADER;
1364
        return 0;
1365
    }
1366

    
1367
    /* If this is WMP, get the rate information */
1368
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1369
        if (modify_current_stream(c, ratebuf)) {
1370
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1371
                if (c->switch_feed_streams[i] >= 0)
1372
                    do_switch_stream(c, i);
1373
            }
1374
        }
1375
    }
1376

    
1377
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1378
        current_bandwidth += stream->bandwidth;
1379

    
1380
    /* If already streaming this feed, do not let start another feeder. */
1381
    if (stream->feed_opened) {
1382
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1383
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1384
        goto send_error;
1385
    }
1386

    
1387
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1388
        c->http_error = 200;
1389
        q = c->buffer;
1390
        q += snprintf(q, c->buffer_size,
1391
                      "HTTP/1.0 200 Server too busy\r\n"
1392
                      "Content-type: text/html\r\n"
1393
                      "\r\n"
1394
                      "<html><head><title>Too busy</title></head><body>\r\n"
1395
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1396
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1397
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1398
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1399
        /* prepare output buffer */
1400
        c->buffer_ptr = c->buffer;
1401
        c->buffer_end = q;
1402
        c->state = HTTPSTATE_SEND_HEADER;
1403
        return 0;
1404
    }
1405

    
1406
    if (redir_type != REDIR_NONE) {
1407
        char *hostinfo = 0;
1408

    
1409
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1410
            if (strncasecmp(p, "Host:", 5) == 0) {
1411
                hostinfo = p + 5;
1412
                break;
1413
            }
1414
            p = strchr(p, '\n');
1415
            if (!p)
1416
                break;
1417

    
1418
            p++;
1419
        }
1420

    
1421
        if (hostinfo) {
1422
            char *eoh;
1423
            char hostbuf[260];
1424

    
1425
            while (isspace(*hostinfo))
1426
                hostinfo++;
1427

    
1428
            eoh = strchr(hostinfo, '\n');
1429
            if (eoh) {
1430
                if (eoh[-1] == '\r')
1431
                    eoh--;
1432

    
1433
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1434
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1435
                    hostbuf[eoh - hostinfo] = 0;
1436

    
1437
                    c->http_error = 200;
1438
                    q = c->buffer;
1439
                    switch(redir_type) {
1440
                    case REDIR_ASX:
1441
                        q += snprintf(q, c->buffer_size,
1442
                                      "HTTP/1.0 200 ASX Follows\r\n"
1443
                                      "Content-type: video/x-ms-asf\r\n"
1444
                                      "\r\n"
1445
                                      "<ASX Version=\"3\">\r\n"
1446
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1447
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1448
                                      "</ASX>\r\n", hostbuf, filename, info);
1449
                        break;
1450
                    case REDIR_RAM:
1451
                        q += snprintf(q, c->buffer_size,
1452
                                      "HTTP/1.0 200 RAM Follows\r\n"
1453
                                      "Content-type: audio/x-pn-realaudio\r\n"
1454
                                      "\r\n"
1455
                                      "# Autogenerated by ffserver\r\n"
1456
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1457
                        break;
1458
                    case REDIR_ASF:
1459
                        q += snprintf(q, c->buffer_size,
1460
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1461
                                      "Content-type: video/x-ms-asf\r\n"
1462
                                      "\r\n"
1463
                                      "[Reference]\r\n"
1464
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1465
                        break;
1466
                    case REDIR_RTSP:
1467
                        {
1468
                            char hostname[256], *p;
1469
                            /* extract only hostname */
1470
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1471
                            p = strrchr(hostname, ':');
1472
                            if (p)
1473
                                *p = '\0';
1474
                            q += snprintf(q, c->buffer_size,
1475
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1476
                                          /* XXX: incorrect mime type ? */
1477
                                          "Content-type: application/x-rtsp\r\n"
1478
                                          "\r\n"
1479
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1480
                        }
1481
                        break;
1482
                    case REDIR_SDP:
1483
                        {
1484
                            uint8_t *sdp_data;
1485
                            int sdp_data_size, len;
1486
                            struct sockaddr_in my_addr;
1487

    
1488
                            q += snprintf(q, c->buffer_size,
1489
                                          "HTTP/1.0 200 OK\r\n"
1490
                                          "Content-type: application/sdp\r\n"
1491
                                          "\r\n");
1492

    
1493
                            len = sizeof(my_addr);
1494
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1495

    
1496
                            /* XXX: should use a dynamic buffer */
1497
                            sdp_data_size = prepare_sdp_description(stream,
1498
                                                                    &sdp_data,
1499
                                                                    my_addr.sin_addr);
1500
                            if (sdp_data_size > 0) {
1501
                                memcpy(q, sdp_data, sdp_data_size);
1502
                                q += sdp_data_size;
1503
                                *q = '\0';
1504
                                av_free(sdp_data);
1505
                            }
1506
                        }
1507
                        break;
1508
                    default:
1509
                        abort();
1510
                        break;
1511
                    }
1512

    
1513
                    /* prepare output buffer */
1514
                    c->buffer_ptr = c->buffer;
1515
                    c->buffer_end = q;
1516
                    c->state = HTTPSTATE_SEND_HEADER;
1517
                    return 0;
1518
                }
1519
            }
1520
        }
1521

    
1522
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1523
        goto send_error;
1524
    }
1525

    
1526
    stream->conns_served++;
1527

    
1528
    /* XXX: add there authenticate and IP match */
1529

    
1530
    if (c->post) {
1531
        /* if post, it means a feed is being sent */
1532
        if (!stream->is_feed) {
1533
            /* However it might be a status report from WMP! Let us log the
1534
             * data as it might come in handy one day. */
1535
            char *logline = 0;
1536
            int client_id = 0;
1537

    
1538
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1539
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1540
                    logline = p;
1541
                    break;
1542
                }
1543
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1544
                    client_id = strtol(p + 18, 0, 10);
1545
                p = strchr(p, '\n');
1546
                if (!p)
1547
                    break;
1548

    
1549
                p++;
1550
            }
1551

    
1552
            if (logline) {
1553
                char *eol = strchr(logline, '\n');
1554

    
1555
                logline += 17;
1556

    
1557
                if (eol) {
1558
                    if (eol[-1] == '\r')
1559
                        eol--;
1560
                    http_log("%.*s\n", (int) (eol - logline), logline);
1561
                    c->suppress_log = 1;
1562
                }
1563
            }
1564

    
1565
#ifdef DEBUG_WMP
1566
            http_log("\nGot request:\n%s\n", c->buffer);
1567
#endif
1568

    
1569
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1570
                HTTPContext *wmpc;
1571

    
1572
                /* Now we have to find the client_id */
1573
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1574
                    if (wmpc->wmp_client_id == client_id)
1575
                        break;
1576
                }
1577

    
1578
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1579
                    wmpc->switch_pending = 1;
1580
            }
1581

    
1582
            snprintf(msg, sizeof(msg), "POST command not handled");
1583
            c->stream = 0;
1584
            goto send_error;
1585
        }
1586
        if (http_start_receive_data(c) < 0) {
1587
            snprintf(msg, sizeof(msg), "could not open feed");
1588
            goto send_error;
1589
        }
1590
        c->http_error = 0;
1591
        c->state = HTTPSTATE_RECEIVE_DATA;
1592
        return 0;
1593
    }
1594

    
1595
#ifdef DEBUG_WMP
1596
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1597
        http_log("\nGot request:\n%s\n", c->buffer);
1598
#endif
1599

    
1600
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1601
        goto send_status;
1602

    
1603
    /* open input stream */
1604
    if (open_input_stream(c, info) < 0) {
1605
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1606
        goto send_error;
1607
    }
1608

    
1609
    /* prepare http header */
1610
    q = c->buffer;
1611
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1612
    mime_type = c->stream->fmt->mime_type;
1613
    if (!mime_type)
1614
        mime_type = "application/x-octet-stream";
1615
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1616

    
1617
    /* for asf, we need extra headers */
1618
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1619
        /* Need to allocate a client id */
1620

    
1621
        c->wmp_client_id = av_lfg_get(&random_state);
1622

    
1623
        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);
1624
    }
1625
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1626
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1627

    
1628
    /* prepare output buffer */
1629
    c->http_error = 0;
1630
    c->buffer_ptr = c->buffer;
1631
    c->buffer_end = q;
1632
    c->state = HTTPSTATE_SEND_HEADER;
1633
    return 0;
1634
 send_error:
1635
    c->http_error = 404;
1636
    q = c->buffer;
1637
    q += snprintf(q, c->buffer_size,
1638
                  "HTTP/1.0 404 Not Found\r\n"
1639
                  "Content-type: text/html\r\n"
1640
                  "\r\n"
1641
                  "<HTML>\n"
1642
                  "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
1643
                  "<BODY>%s</BODY>\n"
1644
                  "</HTML>\n", msg);
1645
    /* prepare output buffer */
1646
    c->buffer_ptr = c->buffer;
1647
    c->buffer_end = q;
1648
    c->state = HTTPSTATE_SEND_HEADER;
1649
    return 0;
1650
 send_status:
1651
    compute_status(c);
1652
    c->http_error = 200; /* horrible : we use this value to avoid
1653
                            going to the send data state */
1654
    c->state = HTTPSTATE_SEND_HEADER;
1655
    return 0;
1656
}
1657

    
1658
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1659
{
1660
    static const char *suffix = " kMGTP";
1661
    const char *s;
1662

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

    
1665
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1666
}
1667

    
1668
static void compute_status(HTTPContext *c)
1669
{
1670
    HTTPContext *c1;
1671
    FFStream *stream;
1672
    char *p;
1673
    time_t ti;
1674
    int i, len;
1675
    ByteIOContext *pb;
1676

    
1677
    if (url_open_dyn_buf(&pb) < 0) {
1678
        /* XXX: return an error ? */
1679
        c->buffer_ptr = c->buffer;
1680
        c->buffer_end = c->buffer;
1681
        return;
1682
    }
1683

    
1684
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1685
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1686
    url_fprintf(pb, "Pragma: no-cache\r\n");
1687
    url_fprintf(pb, "\r\n");
1688

    
1689
    url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
1690
    if (c->stream->feed_filename[0])
1691
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1692
    url_fprintf(pb, "</HEAD>\n<BODY>");
1693
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1694
    /* format status */
1695
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1696
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1697
    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");
1698
    stream = first_stream;
1699
    while (stream != NULL) {
1700
        char sfilename[1024];
1701
        char *eosf;
1702

    
1703
        if (stream->feed != stream) {
1704
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1705
            eosf = sfilename + strlen(sfilename);
1706
            if (eosf - sfilename >= 4) {
1707
                if (strcmp(eosf - 4, ".asf") == 0)
1708
                    strcpy(eosf - 4, ".asx");
1709
                else if (strcmp(eosf - 3, ".rm") == 0)
1710
                    strcpy(eosf - 3, ".ram");
1711
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1712
                    /* generate a sample RTSP director if
1713
                       unicast. Generate an SDP redirector if
1714
                       multicast */
1715
                    eosf = strrchr(sfilename, '.');
1716
                    if (!eosf)
1717
                        eosf = sfilename + strlen(sfilename);
1718
                    if (stream->is_multicast)
1719
                        strcpy(eosf, ".sdp");
1720
                    else
1721
                        strcpy(eosf, ".rtsp");
1722
                }
1723
            }
1724

    
1725
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1726
                         sfilename, stream->filename);
1727
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1728
                        stream->conns_served);
1729
            fmt_bytecount(pb, stream->bytes_served);
1730
            switch(stream->stream_type) {
1731
            case STREAM_TYPE_LIVE: {
1732
                    int audio_bit_rate = 0;
1733
                    int video_bit_rate = 0;
1734
                    const char *audio_codec_name = "";
1735
                    const char *video_codec_name = "";
1736
                    const char *audio_codec_name_extra = "";
1737
                    const char *video_codec_name_extra = "";
1738

    
1739
                    for(i=0;i<stream->nb_streams;i++) {
1740
                        AVStream *st = stream->streams[i];
1741
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1742
                        switch(st->codec->codec_type) {
1743
                        case CODEC_TYPE_AUDIO:
1744
                            audio_bit_rate += st->codec->bit_rate;
1745
                            if (codec) {
1746
                                if (*audio_codec_name)
1747
                                    audio_codec_name_extra = "...";
1748
                                audio_codec_name = codec->name;
1749
                            }
1750
                            break;
1751
                        case CODEC_TYPE_VIDEO:
1752
                            video_bit_rate += st->codec->bit_rate;
1753
                            if (codec) {
1754
                                if (*video_codec_name)
1755
                                    video_codec_name_extra = "...";
1756
                                video_codec_name = codec->name;
1757
                            }
1758
                            break;
1759
                        case CODEC_TYPE_DATA:
1760
                            video_bit_rate += st->codec->bit_rate;
1761
                            break;
1762
                        default:
1763
                            abort();
1764
                        }
1765
                    }
1766
                    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",
1767
                                 stream->fmt->name,
1768
                                 stream->bandwidth,
1769
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1770
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1771
                    if (stream->feed)
1772
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1773
                    else
1774
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1775
                    url_fprintf(pb, "\n");
1776
                }
1777
                break;
1778
            default:
1779
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1780
                break;
1781
            }
1782
        }
1783
        stream = stream->next;
1784
    }
1785
    url_fprintf(pb, "</TABLE>\n");
1786

    
1787
    stream = first_stream;
1788
    while (stream != NULL) {
1789
        if (stream->feed == stream) {
1790
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1791
            if (stream->pid) {
1792
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1793

    
1794
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1795
                {
1796
                    FILE *pid_stat;
1797
                    char ps_cmd[64];
1798

    
1799
                    /* This is somewhat linux specific I guess */
1800
                    snprintf(ps_cmd, sizeof(ps_cmd),
1801
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1802
                             stream->pid);
1803

    
1804
                    pid_stat = popen(ps_cmd, "r");
1805
                    if (pid_stat) {
1806
                        char cpuperc[10];
1807
                        char cpuused[64];
1808

    
1809
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1810
                                   cpuused) == 2) {
1811
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1812
                                         cpuperc, cpuused);
1813
                        }
1814
                        fclose(pid_stat);
1815
                    }
1816
                }
1817
#endif
1818

    
1819
                url_fprintf(pb, "<p>");
1820
            }
1821
            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");
1822

    
1823
            for (i = 0; i < stream->nb_streams; i++) {
1824
                AVStream *st = stream->streams[i];
1825
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1826
                const char *type = "unknown";
1827
                char parameters[64];
1828

    
1829
                parameters[0] = 0;
1830

    
1831
                switch(st->codec->codec_type) {
1832
                case CODEC_TYPE_AUDIO:
1833
                    type = "audio";
1834
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1835
                    break;
1836
                case CODEC_TYPE_VIDEO:
1837
                    type = "video";
1838
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1839
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1840
                    break;
1841
                default:
1842
                    abort();
1843
                }
1844
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1845
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1846
            }
1847
            url_fprintf(pb, "</table>\n");
1848

    
1849
        }
1850
        stream = stream->next;
1851
    }
1852

    
1853
#if 0
1854
    {
1855
        float avg;
1856
        AVCodecContext *enc;
1857
        char buf[1024];
1858

1859
        /* feed status */
1860
        stream = first_feed;
1861
        while (stream != NULL) {
1862
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1863
            url_fprintf(pb, "<TABLE>\n");
1864
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1865
            for(i=0;i<stream->nb_streams;i++) {
1866
                AVStream *st = stream->streams[i];
1867
                FeedData *fdata = st->priv_data;
1868
                enc = st->codec;
1869

1870
                avcodec_string(buf, sizeof(buf), enc);
1871
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1872
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1873
                    avg /= enc->frame_size;
1874
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1875
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1876
            }
1877
            url_fprintf(pb, "</TABLE>\n");
1878
            stream = stream->next_feed;
1879
        }
1880
    }
1881
#endif
1882

    
1883
    /* connection status */
1884
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1885

    
1886
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1887
                 nb_connections, nb_max_connections);
1888

    
1889
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<BR>\n",
1890
                 current_bandwidth, max_bandwidth);
1891

    
1892
    url_fprintf(pb, "<TABLE>\n");
1893
    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");
1894
    c1 = first_http_ctx;
1895
    i = 0;
1896
    while (c1 != NULL) {
1897
        int bitrate;
1898
        int j;
1899

    
1900
        bitrate = 0;
1901
        if (c1->stream) {
1902
            for (j = 0; j < c1->stream->nb_streams; j++) {
1903
                if (!c1->stream->feed)
1904
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1905
                else if (c1->feed_streams[j] >= 0)
1906
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1907
            }
1908
        }
1909

    
1910
        i++;
1911
        p = inet_ntoa(c1->from_addr.sin_addr);
1912
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1913
                    i,
1914
                    c1->stream ? c1->stream->filename : "",
1915
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1916
                    p,
1917
                    c1->protocol,
1918
                    http_state[c1->state]);
1919
        fmt_bytecount(pb, bitrate);
1920
        url_fprintf(pb, "<td align=right>");
1921
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1922
        url_fprintf(pb, "<td align=right>");
1923
        fmt_bytecount(pb, c1->data_count);
1924
        url_fprintf(pb, "\n");
1925
        c1 = c1->next;
1926
    }
1927
    url_fprintf(pb, "</TABLE>\n");
1928

    
1929
    /* date */
1930
    ti = time(NULL);
1931
    p = ctime(&ti);
1932
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1933
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1934

    
1935
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1936
    c->buffer_ptr = c->pb_buffer;
1937
    c->buffer_end = c->pb_buffer + len;
1938
}
1939

    
1940
/* check if the parser needs to be opened for stream i */
1941
static void open_parser(AVFormatContext *s, int i)
1942
{
1943
    AVStream *st = s->streams[i];
1944
    AVCodec *codec;
1945

    
1946
    if (!st->codec->codec) {
1947
        codec = avcodec_find_decoder(st->codec->codec_id);
1948
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1949
            st->codec->parse_only = 1;
1950
            if (avcodec_open(st->codec, codec) < 0)
1951
                st->codec->parse_only = 0;
1952
        }
1953
    }
1954
}
1955

    
1956
static int open_input_stream(HTTPContext *c, const char *info)
1957
{
1958
    char buf[128];
1959
    char input_filename[1024];
1960
    AVFormatContext *s;
1961
    int buf_size, i, ret;
1962
    int64_t stream_pos;
1963

    
1964
    /* find file name */
1965
    if (c->stream->feed) {
1966
        strcpy(input_filename, c->stream->feed->feed_filename);
1967
        buf_size = FFM_PACKET_SIZE;
1968
        /* compute position (absolute time) */
1969
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1970
            stream_pos = parse_date(buf, 0);
1971
            if (stream_pos == INT64_MIN)
1972
                return -1;
1973
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1974
            int prebuffer = strtol(buf, 0, 10);
1975
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1976
        } else
1977
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1978
    } else {
1979
        strcpy(input_filename, c->stream->feed_filename);
1980
        buf_size = 0;
1981
        /* compute position (relative time) */
1982
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1983
            stream_pos = parse_date(buf, 1);
1984
            if (stream_pos == INT64_MIN)
1985
                return -1;
1986
        } else
1987
            stream_pos = 0;
1988
    }
1989
    if (input_filename[0] == '\0')
1990
        return -1;
1991

    
1992
#if 0
1993
    { time_t when = stream_pos / 1000000;
1994
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1995
    }
1996
#endif
1997

    
1998
    /* open stream */
1999
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2000
                                  buf_size, c->stream->ap_in)) < 0) {
2001
        http_log("could not open %s: %d\n", input_filename, ret);
2002
        return -1;
2003
    }
2004
    s->flags |= AVFMT_FLAG_GENPTS;
2005
    c->fmt_in = s;
2006
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2007
        http_log("Could not find stream info '%s'\n", input_filename);
2008
        av_close_input_file(s);
2009
        return -1;
2010
    }
2011

    
2012
    /* open each parser */
2013
    for(i=0;i<s->nb_streams;i++)
2014
        open_parser(s, i);
2015

    
2016
    /* choose stream as clock source (we favorize video stream if
2017
       present) for packet sending */
2018
    c->pts_stream_index = 0;
2019
    for(i=0;i<c->stream->nb_streams;i++) {
2020
        if (c->pts_stream_index == 0 &&
2021
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2022
            c->pts_stream_index = i;
2023
        }
2024
    }
2025

    
2026
#if 1
2027
    if (c->fmt_in->iformat->read_seek)
2028
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2029
#endif
2030
    /* set the start time (needed for maxtime and RTP packet timing) */
2031
    c->start_time = cur_time;
2032
    c->first_pts = AV_NOPTS_VALUE;
2033
    return 0;
2034
}
2035

    
2036
/* return the server clock (in us) */
2037
static int64_t get_server_clock(HTTPContext *c)
2038
{
2039
    /* compute current pts value from system time */
2040
    return (cur_time - c->start_time) * 1000;
2041
}
2042

    
2043
/* return the estimated time at which the current packet must be sent
2044
   (in us) */
2045
static int64_t get_packet_send_clock(HTTPContext *c)
2046
{
2047
    int bytes_left, bytes_sent, frame_bytes;
2048

    
2049
    frame_bytes = c->cur_frame_bytes;
2050
    if (frame_bytes <= 0)
2051
        return c->cur_pts;
2052
    else {
2053
        bytes_left = c->buffer_end - c->buffer_ptr;
2054
        bytes_sent = frame_bytes - bytes_left;
2055
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2056
    }
2057
}
2058

    
2059

    
2060
static int http_prepare_data(HTTPContext *c)
2061
{
2062
    int i, len, ret;
2063
    AVFormatContext *ctx;
2064

    
2065
    av_freep(&c->pb_buffer);
2066
    switch(c->state) {
2067
    case HTTPSTATE_SEND_DATA_HEADER:
2068
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2069
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2070
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2071
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2072
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2073

    
2074
        for(i=0;i<c->stream->nb_streams;i++) {
2075
            AVStream *st;
2076
            AVStream *src;
2077
            st = av_mallocz(sizeof(AVStream));
2078
            c->fmt_ctx.streams[i] = st;
2079
            /* if file or feed, then just take streams from FFStream struct */
2080
            if (!c->stream->feed ||
2081
                c->stream->feed == c->stream)
2082
                src = c->stream->streams[i];
2083
            else
2084
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2085

    
2086
            *st = *src;
2087
            st->priv_data = 0;
2088
            st->codec->frame_number = 0; /* XXX: should be done in
2089
                                           AVStream, not in codec */
2090
        }
2091
        /* set output format parameters */
2092
        c->fmt_ctx.oformat = c->stream->fmt;
2093
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2094

    
2095
        c->got_key_frame = 0;
2096

    
2097
        /* prepare header and save header data in a stream */
2098
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2099
            /* XXX: potential leak */
2100
            return -1;
2101
        }
2102
        c->fmt_ctx.pb->is_streamed = 1;
2103

    
2104
        /*
2105
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2106
         * Default value from FFmpeg
2107
         * Try to set it use configuration option
2108
         */
2109
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2110
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2111

    
2112
        av_set_parameters(&c->fmt_ctx, NULL);
2113
        if (av_write_header(&c->fmt_ctx) < 0) {
2114
            http_log("Error writing output header\n");
2115
            return -1;
2116
        }
2117

    
2118
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2119
        c->buffer_ptr = c->pb_buffer;
2120
        c->buffer_end = c->pb_buffer + len;
2121

    
2122
        c->state = HTTPSTATE_SEND_DATA;
2123
        c->last_packet_sent = 0;
2124
        break;
2125
    case HTTPSTATE_SEND_DATA:
2126
        /* find a new packet */
2127
        /* read a packet from the input stream */
2128
        if (c->stream->feed)
2129
            ffm_set_write_index(c->fmt_in,
2130
                                c->stream->feed->feed_write_index,
2131
                                c->stream->feed->feed_size);
2132

    
2133
        if (c->stream->max_time &&
2134
            c->stream->max_time + c->start_time - cur_time < 0)
2135
            /* We have timed out */
2136
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2137
        else {
2138
            AVPacket pkt;
2139
        redo:
2140
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2141
                if (c->stream->feed && c->stream->feed->feed_opened) {
2142
                    /* if coming from feed, it means we reached the end of the
2143
                       ffm file, so must wait for more data */
2144
                    c->state = HTTPSTATE_WAIT_FEED;
2145
                    return 1; /* state changed */
2146
                } else {
2147
                    if (c->stream->loop) {
2148
                        av_close_input_file(c->fmt_in);
2149
                        c->fmt_in = NULL;
2150
                        if (open_input_stream(c, "") < 0)
2151
                            goto no_loop;
2152
                        goto redo;
2153
                    } else {
2154
                    no_loop:
2155
                        /* must send trailer now because eof or error */
2156
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2157
                    }
2158
                }
2159
            } else {
2160
                int source_index = pkt.stream_index;
2161
                /* update first pts if needed */
2162
                if (c->first_pts == AV_NOPTS_VALUE) {
2163
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2164
                    c->start_time = cur_time;
2165
                }
2166
                /* send it to the appropriate stream */
2167
                if (c->stream->feed) {
2168
                    /* if coming from a feed, select the right stream */
2169
                    if (c->switch_pending) {
2170
                        c->switch_pending = 0;
2171
                        for(i=0;i<c->stream->nb_streams;i++) {
2172
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2173
                                if (pkt.flags & PKT_FLAG_KEY)
2174
                                    do_switch_stream(c, i);
2175
                            if (c->switch_feed_streams[i] >= 0)
2176
                                c->switch_pending = 1;
2177
                        }
2178
                    }
2179
                    for(i=0;i<c->stream->nb_streams;i++) {
2180
                        if (c->feed_streams[i] == pkt.stream_index) {
2181
                            AVStream *st = c->fmt_in->streams[source_index];
2182
                            pkt.stream_index = i;
2183
                            if (pkt.flags & PKT_FLAG_KEY &&
2184
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2185
                                 c->stream->nb_streams == 1))
2186
                                c->got_key_frame = 1;
2187
                            if (!c->stream->send_on_key || c->got_key_frame)
2188
                                goto send_it;
2189
                        }
2190
                    }
2191
                } else {
2192
                    AVCodecContext *codec;
2193
                    AVStream *ist, *ost;
2194
                send_it:
2195
                    ist = c->fmt_in->streams[source_index];
2196
                    /* specific handling for RTP: we use several
2197
                       output stream (one for each RTP
2198
                       connection). XXX: need more abstract handling */
2199
                    if (c->is_packetized) {
2200
                        /* compute send time and duration */
2201
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2202
                        if (ist->start_time != AV_NOPTS_VALUE)
2203
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2204
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2205
#if 0
2206
                        printf("index=%d pts=%0.3f duration=%0.6f\n",
2207
                               pkt.stream_index,
2208
                               (double)c->cur_pts /
2209
                               AV_TIME_BASE,
2210
                               (double)c->cur_frame_duration /
2211
                               AV_TIME_BASE);
2212
#endif
2213
                        /* find RTP context */
2214
                        c->packet_stream_index = pkt.stream_index;
2215
                        ctx = c->rtp_ctx[c->packet_stream_index];
2216
                        if(!ctx) {
2217
                            av_free_packet(&pkt);
2218
                            break;
2219
                        }
2220
                        codec = ctx->streams[0]->codec;
2221
                        /* only one stream per RTP connection */
2222
                        pkt.stream_index = 0;
2223
                    } else {
2224
                        ctx = &c->fmt_ctx;
2225
                        /* Fudge here */
2226
                        codec = ctx->streams[pkt.stream_index]->codec;
2227
                    }
2228

    
2229
                    if (c->is_packetized) {
2230
                        int max_packet_size;
2231
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2232
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2233
                        else
2234
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2235
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2236
                    } else {
2237
                        ret = url_open_dyn_buf(&ctx->pb);
2238
                    }
2239
                    if (ret < 0) {
2240
                        /* XXX: potential leak */
2241
                        return -1;
2242
                    }
2243
                    ost = ctx->streams[pkt.stream_index];
2244

    
2245
                    ctx->pb->is_streamed = 1;
2246
                    if (pkt.dts != AV_NOPTS_VALUE)
2247
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2248
                    if (pkt.pts != AV_NOPTS_VALUE)
2249
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2250
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2251
                    if (av_write_frame(ctx, &pkt) < 0) {
2252
                        http_log("Error writing frame to output\n");
2253
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2254
                    }
2255

    
2256
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2257
                    c->cur_frame_bytes = len;
2258
                    c->buffer_ptr = c->pb_buffer;
2259
                    c->buffer_end = c->pb_buffer + len;
2260

    
2261
                    codec->frame_number++;
2262
                    if (len == 0) {
2263
                        av_free_packet(&pkt);
2264
                        goto redo;
2265
                    }
2266
                }
2267
                av_free_packet(&pkt);
2268
            }
2269
        }
2270
        break;
2271
    default:
2272
    case HTTPSTATE_SEND_DATA_TRAILER:
2273
        /* last packet test ? */
2274
        if (c->last_packet_sent || c->is_packetized)
2275
            return -1;
2276
        ctx = &c->fmt_ctx;
2277
        /* prepare header */
2278
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2279
            /* XXX: potential leak */
2280
            return -1;
2281
        }
2282
        c->fmt_ctx.pb->is_streamed = 1;
2283
        av_write_trailer(ctx);
2284
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2285
        c->buffer_ptr = c->pb_buffer;
2286
        c->buffer_end = c->pb_buffer + len;
2287

    
2288
        c->last_packet_sent = 1;
2289
        break;
2290
    }
2291
    return 0;
2292
}
2293

    
2294
/* should convert the format at the same time */
2295
/* send data starting at c->buffer_ptr to the output connection
2296
   (either UDP or TCP connection) */
2297
static int http_send_data(HTTPContext *c)
2298
{
2299
    int len, ret;
2300

    
2301
    for(;;) {
2302
        if (c->buffer_ptr >= c->buffer_end) {
2303
            ret = http_prepare_data(c);
2304
            if (ret < 0)
2305
                return -1;
2306
            else if (ret != 0)
2307
                /* state change requested */
2308
                break;
2309
        } else {
2310
            if (c->is_packetized) {
2311
                /* RTP data output */
2312
                len = c->buffer_end - c->buffer_ptr;
2313
                if (len < 4) {
2314
                    /* fail safe - should never happen */
2315
                fail1:
2316
                    c->buffer_ptr = c->buffer_end;
2317
                    return 0;
2318
                }
2319
                len = (c->buffer_ptr[0] << 24) |
2320
                    (c->buffer_ptr[1] << 16) |
2321
                    (c->buffer_ptr[2] << 8) |
2322
                    (c->buffer_ptr[3]);
2323
                if (len > (c->buffer_end - c->buffer_ptr))
2324
                    goto fail1;
2325
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2326
                    /* nothing to send yet: we can wait */
2327
                    return 0;
2328
                }
2329

    
2330
                c->data_count += len;
2331
                update_datarate(&c->datarate, c->data_count);
2332
                if (c->stream)
2333
                    c->stream->bytes_served += len;
2334

    
2335
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2336
                    /* RTP packets are sent inside the RTSP TCP connection */
2337
                    ByteIOContext *pb;
2338
                    int interleaved_index, size;
2339
                    uint8_t header[4];
2340
                    HTTPContext *rtsp_c;
2341

    
2342
                    rtsp_c = c->rtsp_c;
2343
                    /* if no RTSP connection left, error */
2344
                    if (!rtsp_c)
2345
                        return -1;
2346
                    /* if already sending something, then wait. */
2347
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2348
                        break;
2349
                    if (url_open_dyn_buf(&pb) < 0)
2350
                        goto fail1;
2351
                    interleaved_index = c->packet_stream_index * 2;
2352
                    /* RTCP packets are sent at odd indexes */
2353
                    if (c->buffer_ptr[1] == 200)
2354
                        interleaved_index++;
2355
                    /* write RTSP TCP header */
2356
                    header[0] = '$';
2357
                    header[1] = interleaved_index;
2358
                    header[2] = len >> 8;
2359
                    header[3] = len;
2360
                    put_buffer(pb, header, 4);
2361
                    /* write RTP packet data */
2362
                    c->buffer_ptr += 4;
2363
                    put_buffer(pb, c->buffer_ptr, len);
2364
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2365
                    /* prepare asynchronous TCP sending */
2366
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2367
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2368
                    c->buffer_ptr += len;
2369

    
2370
                    /* send everything we can NOW */
2371
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2372
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2373
                    if (len > 0)
2374
                        rtsp_c->packet_buffer_ptr += len;
2375
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2376
                        /* if we could not send all the data, we will
2377
                           send it later, so a new state is needed to
2378
                           "lock" the RTSP TCP connection */
2379
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2380
                        break;
2381
                    } else
2382
                        /* all data has been sent */
2383
                        av_freep(&c->packet_buffer);
2384
                } else {
2385
                    /* send RTP packet directly in UDP */
2386
                    c->buffer_ptr += 4;
2387
                    url_write(c->rtp_handles[c->packet_stream_index],
2388
                              c->buffer_ptr, len);
2389
                    c->buffer_ptr += len;
2390
                    /* here we continue as we can send several packets per 10 ms slot */
2391
                }
2392
            } else {
2393
                /* TCP data output */
2394
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2395
                if (len < 0) {
2396
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2397
                        ff_neterrno() != FF_NETERROR(EINTR))
2398
                        /* error : close connection */
2399
                        return -1;
2400
                    else
2401
                        return 0;
2402
                } else
2403
                    c->buffer_ptr += len;
2404

    
2405
                c->data_count += len;
2406
                update_datarate(&c->datarate, c->data_count);
2407
                if (c->stream)
2408
                    c->stream->bytes_served += len;
2409
                break;
2410
            }
2411
        }
2412
    } /* for(;;) */
2413
    return 0;
2414
}
2415

    
2416
static int http_start_receive_data(HTTPContext *c)
2417
{
2418
    int fd;
2419

    
2420
    if (c->stream->feed_opened)
2421
        return -1;
2422

    
2423
    /* Don't permit writing to this one */
2424
    if (c->stream->readonly)
2425
        return -1;
2426

    
2427
    /* open feed */
2428
    fd = open(c->stream->feed_filename, O_RDWR);
2429
    if (fd < 0) {
2430
        http_log("Error opening feeder file: %s\n", strerror(errno));
2431
        return -1;
2432
    }
2433
    c->feed_fd = fd;
2434

    
2435
    if (c->stream->truncate) {
2436
        /* truncate feed file */
2437
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2438
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2439
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2440
    } else {
2441
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2442
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2443
            return -1;
2444
        }
2445
    }
2446

    
2447
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2448
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2449
    lseek(fd, 0, SEEK_SET);
2450

    
2451
    /* init buffer input */
2452
    c->buffer_ptr = c->buffer;
2453
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2454
    c->stream->feed_opened = 1;
2455
    return 0;
2456
}
2457

    
2458
static int http_receive_data(HTTPContext *c)
2459
{
2460
    HTTPContext *c1;
2461

    
2462
    if (c->buffer_end > c->buffer_ptr) {
2463
        int len;
2464

    
2465
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2466
        if (len < 0) {
2467
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2468
                ff_neterrno() != FF_NETERROR(EINTR))
2469
                /* error : close connection */
2470
                goto fail;
2471
        } else if (len == 0)
2472
            /* end of connection : close it */
2473
            goto fail;
2474
        else {
2475
            c->buffer_ptr += len;
2476
            c->data_count += len;
2477
            update_datarate(&c->datarate, c->data_count);
2478
        }
2479
    }
2480

    
2481
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2482
        if (c->buffer[0] != 'f' ||
2483
            c->buffer[1] != 'm') {
2484
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2485
            goto fail;
2486
        }
2487
    }
2488

    
2489
    if (c->buffer_ptr >= c->buffer_end) {
2490
        FFStream *feed = c->stream;
2491
        /* a packet has been received : write it in the store, except
2492
           if header */
2493
        if (c->data_count > FFM_PACKET_SIZE) {
2494

    
2495
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2496
            /* XXX: use llseek or url_seek */
2497
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2498
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2499
                http_log("Error writing to feed file: %s\n", strerror(errno));
2500
                goto fail;
2501
            }
2502

    
2503
            feed->feed_write_index += FFM_PACKET_SIZE;
2504
            /* update file size */
2505
            if (feed->feed_write_index > c->stream->feed_size)
2506
                feed->feed_size = feed->feed_write_index;
2507

    
2508
            /* handle wrap around if max file size reached */
2509
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2510
                feed->feed_write_index = FFM_PACKET_SIZE;
2511

    
2512
            /* write index */
2513
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2514
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2515
                goto fail;
2516
            }
2517

    
2518
            /* wake up any waiting connections */
2519
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2520
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2521
                    c1->stream->feed == c->stream->feed)
2522
                    c1->state = HTTPSTATE_SEND_DATA;
2523
            }
2524
        } else {
2525
            /* We have a header in our hands that contains useful data */
2526
            AVFormatContext *s = NULL;
2527
            ByteIOContext *pb;
2528
            AVInputFormat *fmt_in;
2529
            int i;
2530

    
2531
            /* use feed output format name to find corresponding input format */
2532
            fmt_in = av_find_input_format(feed->fmt->name);
2533
            if (!fmt_in)
2534
                goto fail;
2535

    
2536
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2537
            pb->is_streamed = 1;
2538

    
2539
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2540
                av_free(pb);
2541
                goto fail;
2542
            }
2543

    
2544
            /* Now we have the actual streams */
2545
            if (s->nb_streams != feed->nb_streams) {
2546
                av_close_input_stream(s);
2547
                av_free(pb);
2548
                http_log("Feed '%s' stream number does not match registered feed\n",
2549
                         c->stream->feed_filename);
2550
                goto fail;
2551
            }
2552

    
2553
            for (i = 0; i < s->nb_streams; i++) {
2554
                AVStream *fst = feed->streams[i];
2555
                AVStream *st = s->streams[i];
2556
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2557
                if (fst->codec->extradata_size) {
2558
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2559
                    if (!fst->codec->extradata)
2560
                        goto fail;
2561
                    memcpy(fst->codec->extradata, st->codec->extradata,
2562
                           fst->codec->extradata_size);
2563
                }
2564
            }
2565

    
2566
            av_close_input_stream(s);
2567
            av_free(pb);
2568
        }
2569
        c->buffer_ptr = c->buffer;
2570
    }
2571

    
2572
    return 0;
2573
 fail:
2574
    c->stream->feed_opened = 0;
2575
    close(c->feed_fd);
2576
    /* wake up any waiting connections to stop waiting for feed */
2577
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2578
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2579
            c1->stream->feed == c->stream->feed)
2580
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2581
    }
2582
    return -1;
2583
}
2584

    
2585
/********************************************************************/
2586
/* RTSP handling */
2587

    
2588
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2589
{
2590
    const char *str;
2591
    time_t ti;
2592
    char *p;
2593
    char buf2[32];
2594

    
2595
    switch(error_number) {
2596
    case RTSP_STATUS_OK:
2597
        str = "OK";
2598
        break;
2599
    case RTSP_STATUS_METHOD:
2600
        str = "Method Not Allowed";
2601
        break;
2602
    case RTSP_STATUS_BANDWIDTH:
2603
        str = "Not Enough Bandwidth";
2604
        break;
2605
    case RTSP_STATUS_SESSION:
2606
        str = "Session Not Found";
2607
        break;
2608
    case RTSP_STATUS_STATE:
2609
        str = "Method Not Valid in This State";
2610
        break;
2611
    case RTSP_STATUS_AGGREGATE:
2612
        str = "Aggregate operation not allowed";
2613
        break;
2614
    case RTSP_STATUS_ONLY_AGGREGATE:
2615
        str = "Only aggregate operation allowed";
2616
        break;
2617
    case RTSP_STATUS_TRANSPORT:
2618
        str = "Unsupported transport";
2619
        break;
2620
    case RTSP_STATUS_INTERNAL:
2621
        str = "Internal Server Error";
2622
        break;
2623
    case RTSP_STATUS_SERVICE:
2624
        str = "Service Unavailable";
2625
        break;
2626
    case RTSP_STATUS_VERSION:
2627
        str = "RTSP Version not supported";
2628
        break;
2629
    default:
2630
        str = "Unknown Error";
2631
        break;
2632
    }
2633

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

    
2637
    /* output GMT time */
2638
    ti = time(NULL);
2639
    p = ctime(&ti);
2640
    strcpy(buf2, p);
2641
    p = buf2 + strlen(p) - 1;
2642
    if (*p == '\n')
2643
        *p = '\0';
2644
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2645
}
2646

    
2647
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2648
{
2649
    rtsp_reply_header(c, error_number);
2650
    url_fprintf(c->pb, "\r\n");
2651
}
2652

    
2653
static int rtsp_parse_request(HTTPContext *c)
2654
{
2655
    const char *p, *p1, *p2;
2656
    char cmd[32];
2657
    char url[1024];
2658
    char protocol[32];
2659
    char line[1024];
2660
    int len;
2661
    RTSPMessageHeader header1, *header = &header1;
2662

    
2663
    c->buffer_ptr[0] = '\0';
2664
    p = c->buffer;
2665

    
2666
    get_word(cmd, sizeof(cmd), &p);
2667
    get_word(url, sizeof(url), &p);
2668
    get_word(protocol, sizeof(protocol), &p);
2669

    
2670
    av_strlcpy(c->method, cmd, sizeof(c->method));
2671
    av_strlcpy(c->url, url, sizeof(c->url));
2672
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2673

    
2674
    if (url_open_dyn_buf(&c->pb) < 0) {
2675
        /* XXX: cannot do more */
2676
        c->pb = NULL; /* safety */
2677
        return -1;
2678
    }
2679

    
2680
    /* check version name */
2681
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2682
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2683
        goto the_end;
2684
    }
2685

    
2686
    /* parse each header line */
2687
    memset(header, 0, sizeof(*header));
2688
    /* skip to next line */
2689
    while (*p != '\n' && *p != '\0')
2690
        p++;
2691
    if (*p == '\n')
2692
        p++;
2693
    while (*p != '\0') {
2694
        p1 = strchr(p, '\n');
2695
        if (!p1)
2696
            break;
2697
        p2 = p1;
2698
        if (p2 > p && p2[-1] == '\r')
2699
            p2--;
2700
        /* skip empty line */
2701
        if (p2 == p)
2702
            break;
2703
        len = p2 - p;
2704
        if (len > sizeof(line) - 1)
2705
            len = sizeof(line) - 1;
2706
        memcpy(line, p, len);
2707
        line[len] = '\0';
2708
        rtsp_parse_line(header, line);
2709
        p = p1 + 1;
2710
    }
2711

    
2712
    /* handle sequence number */
2713
    c->seq = header->seq;
2714

    
2715
    if (!strcmp(cmd, "DESCRIBE"))
2716
        rtsp_cmd_describe(c, url);
2717
    else if (!strcmp(cmd, "OPTIONS"))
2718
        rtsp_cmd_options(c, url);
2719
    else if (!strcmp(cmd, "SETUP"))
2720
        rtsp_cmd_setup(c, url, header);
2721
    else if (!strcmp(cmd, "PLAY"))
2722
        rtsp_cmd_play(c, url, header);
2723
    else if (!strcmp(cmd, "PAUSE"))
2724
        rtsp_cmd_pause(c, url, header);
2725
    else if (!strcmp(cmd, "TEARDOWN"))
2726
        rtsp_cmd_teardown(c, url, header);
2727
    else
2728
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2729

    
2730
 the_end:
2731
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2732
    c->pb = NULL; /* safety */
2733
    if (len < 0) {
2734
        /* XXX: cannot do more */
2735
        return -1;
2736
    }
2737
    c->buffer_ptr = c->pb_buffer;
2738
    c->buffer_end = c->pb_buffer + len;
2739
    c->state = RTSPSTATE_SEND_REPLY;
2740
    return 0;
2741
}
2742

    
2743
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2744
                                   struct in_addr my_ip)
2745
{
2746
    AVFormatContext *avc;
2747
    AVStream avs[MAX_STREAMS];
2748
    int i;
2749

    
2750
    avc =  avformat_alloc_context();
2751
    if (avc == NULL) {
2752
        return -1;
2753
    }
2754
    av_metadata_set(&avc->metadata, "title",
2755
                    stream->title[0] ? stream->title : "No Title");
2756
    avc->nb_streams = stream->nb_streams;
2757
    if (stream->is_multicast) {
2758
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2759
                 inet_ntoa(stream->multicast_ip),
2760
                 stream->multicast_port, stream->multicast_ttl);
2761
    }
2762

    
2763
    for(i = 0; i < stream->nb_streams; i++) {
2764
        avc->streams[i] = &avs[i];
2765
        avc->streams[i]->codec = stream->streams[i]->codec;
2766
    }
2767
    *pbuffer = av_mallocz(2048);
2768
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2769
    av_free(avc);
2770

    
2771
    return strlen(*pbuffer);
2772
}
2773

    
2774
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2775
{
2776
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2777
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2778
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2779
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2780
    url_fprintf(c->pb, "\r\n");
2781
}
2782

    
2783
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2784
{
2785
    FFStream *stream;
2786
    char path1[1024];
2787
    const char *path;
2788
    uint8_t *content;
2789
    int content_length, len;
2790
    struct sockaddr_in my_addr;
2791

    
2792
    /* find which url is asked */
2793
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2794
    path = path1;
2795
    if (*path == '/')
2796
        path++;
2797

    
2798
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2799
        if (!stream->is_feed &&
2800
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2801
            !strcmp(path, stream->filename)) {
2802
            goto found;
2803
        }
2804
    }
2805
    /* no stream found */
2806
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2807
    return;
2808

    
2809
 found:
2810
    /* prepare the media description in sdp format */
2811

    
2812
    /* get the host IP */
2813
    len = sizeof(my_addr);
2814
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2815
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2816
    if (content_length < 0) {
2817
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2818
        return;
2819
    }
2820
    rtsp_reply_header(c, RTSP_STATUS_OK);
2821
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2822
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2823
    url_fprintf(c->pb, "\r\n");
2824
    put_buffer(c->pb, content, content_length);
2825
}
2826

    
2827
static HTTPContext *find_rtp_session(const char *session_id)
2828
{
2829
    HTTPContext *c;
2830

    
2831
    if (session_id[0] == '\0')
2832
        return NULL;
2833

    
2834
    for(c = first_http_ctx; c != NULL; c = c->next) {
2835
        if (!strcmp(c->session_id, session_id))
2836
            return c;
2837
    }
2838
    return NULL;
2839
}
2840

    
2841
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2842
{
2843
    RTSPTransportField *th;
2844
    int i;
2845

    
2846
    for(i=0;i<h->nb_transports;i++) {
2847
        th = &h->transports[i];
2848
        if (th->lower_transport == lower_transport)
2849
            return th;
2850
    }
2851
    return NULL;
2852
}
2853

    
2854
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2855
                           RTSPMessageHeader *h)
2856
{
2857
    FFStream *stream;
2858
    int stream_index, port;
2859
    char buf[1024];
2860
    char path1[1024];
2861
    const char *path;
2862
    HTTPContext *rtp_c;
2863
    RTSPTransportField *th;
2864
    struct sockaddr_in dest_addr;
2865
    RTSPActionServerSetup setup;
2866

    
2867
    /* find which url is asked */
2868
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2869
    path = path1;
2870
    if (*path == '/')
2871
        path++;
2872

    
2873
    /* now check each stream */
2874
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2875
        if (!stream->is_feed &&
2876
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2877
            /* accept aggregate filenames only if single stream */
2878
            if (!strcmp(path, stream->filename)) {
2879
                if (stream->nb_streams != 1) {
2880
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2881
                    return;
2882
                }
2883
                stream_index = 0;
2884
                goto found;
2885
            }
2886

    
2887
            for(stream_index = 0; stream_index < stream->nb_streams;
2888
                stream_index++) {
2889
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2890
                         stream->filename, stream_index);
2891
                if (!strcmp(path, buf))
2892
                    goto found;
2893
            }
2894
        }
2895
    }
2896
    /* no stream found */
2897
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2898
    return;
2899
 found:
2900

    
2901
    /* generate session id if needed */
2902
    if (h->session_id[0] == '\0')
2903
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2904
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2905

    
2906
    /* find rtp session, and create it if none found */
2907
    rtp_c = find_rtp_session(h->session_id);
2908
    if (!rtp_c) {
2909
        /* always prefer UDP */
2910
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2911
        if (!th) {
2912
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2913
            if (!th) {
2914
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2915
                return;
2916
            }
2917
        }
2918

    
2919
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2920
                                   th->lower_transport);
2921
        if (!rtp_c) {
2922
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2923
            return;
2924
        }
2925

    
2926
        /* open input stream */
2927
        if (open_input_stream(rtp_c, "") < 0) {
2928
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2929
            return;
2930
        }
2931
    }
2932

    
2933
    /* test if stream is OK (test needed because several SETUP needs
2934
       to be done for a given file) */
2935
    if (rtp_c->stream != stream) {
2936
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2937
        return;
2938
    }
2939

    
2940
    /* test if stream is already set up */
2941
    if (rtp_c->rtp_ctx[stream_index]) {
2942
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2943
        return;
2944
    }
2945

    
2946
    /* check transport */
2947
    th = find_transport(h, rtp_c->rtp_protocol);
2948
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2949
                th->client_port_min <= 0)) {
2950
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2951
        return;
2952
    }
2953

    
2954
    /* setup default options */
2955
    setup.transport_option[0] = '\0';
2956
    dest_addr = rtp_c->from_addr;
2957
    dest_addr.sin_port = htons(th->client_port_min);
2958

    
2959
    /* setup stream */
2960
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2961
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2962
        return;
2963
    }
2964

    
2965
    /* now everything is OK, so we can send the connection parameters */
2966
    rtsp_reply_header(c, RTSP_STATUS_OK);
2967
    /* session ID */
2968
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2969

    
2970
    switch(rtp_c->rtp_protocol) {
2971
    case RTSP_LOWER_TRANSPORT_UDP:
2972
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2973
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2974
                    "client_port=%d-%d;server_port=%d-%d",
2975
                    th->client_port_min, th->client_port_min + 1,
2976
                    port, port + 1);
2977
        break;
2978
    case RTSP_LOWER_TRANSPORT_TCP:
2979
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2980
                    stream_index * 2, stream_index * 2 + 1);
2981
        break;
2982
    default:
2983
        break;
2984
    }
2985
    if (setup.transport_option[0] != '\0')
2986
        url_fprintf(c->pb, ";%s", setup.transport_option);
2987
    url_fprintf(c->pb, "\r\n");
2988

    
2989

    
2990
    url_fprintf(c->pb, "\r\n");
2991
}
2992

    
2993

    
2994
/* find an rtp connection by using the session ID. Check consistency
2995
   with filename */
2996
static HTTPContext *find_rtp_session_with_url(const char *url,
2997
                                              const char *session_id)
2998
{
2999
    HTTPContext *rtp_c;
3000
    char path1[1024];
3001
    const char *path;
3002
    char buf[1024];
3003
    int s;
3004

    
3005
    rtp_c = find_rtp_session(session_id);
3006
    if (!rtp_c)
3007
        return NULL;
3008

    
3009
    /* find which url is asked */
3010
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3011
    path = path1;
3012
    if (*path == '/')
3013
        path++;
3014
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3015
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3016
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3017
        rtp_c->stream->filename, s);
3018
      if(!strncmp(path, buf, sizeof(buf))) {
3019
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3020
        return rtp_c;
3021
      }
3022
    }
3023
    return NULL;
3024
}
3025

    
3026
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3027
{
3028
    HTTPContext *rtp_c;
3029

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

    
3036
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3037
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3038
        rtp_c->state != HTTPSTATE_READY) {
3039
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3040
        return;
3041
    }
3042

    
3043
#if 0
3044
    /* XXX: seek in stream */
3045
    if (h->range_start != AV_NOPTS_VALUE) {
3046
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3047
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3048
    }
3049
#endif
3050

    
3051
    rtp_c->state = HTTPSTATE_SEND_DATA;
3052

    
3053
    /* now everything is OK, so we can send the connection parameters */
3054
    rtsp_reply_header(c, RTSP_STATUS_OK);
3055
    /* session ID */
3056
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3057
    url_fprintf(c->pb, "\r\n");
3058
}
3059

    
3060
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3061
{
3062
    HTTPContext *rtp_c;
3063

    
3064
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3065
    if (!rtp_c) {
3066
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3067
        return;
3068
    }
3069

    
3070
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3071
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3072
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3073
        return;
3074
    }
3075

    
3076
    rtp_c->state = HTTPSTATE_READY;
3077
    rtp_c->first_pts = AV_NOPTS_VALUE;
3078
    /* now everything is OK, so we can send the connection parameters */
3079
    rtsp_reply_header(c, RTSP_STATUS_OK);
3080
    /* session ID */
3081
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3082
    url_fprintf(c->pb, "\r\n");
3083
}
3084

    
3085
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3086
{
3087
    HTTPContext *rtp_c;
3088
    char session_id[32];
3089

    
3090
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3091
    if (!rtp_c) {
3092
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3093
        return;
3094
    }
3095

    
3096
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3097

    
3098
    /* abort the session */
3099
    close_connection(rtp_c);
3100

    
3101
    /* now everything is OK, so we can send the connection parameters */
3102
    rtsp_reply_header(c, RTSP_STATUS_OK);
3103
    /* session ID */
3104
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3105
    url_fprintf(c->pb, "\r\n");
3106
}
3107

    
3108

    
3109
/********************************************************************/
3110
/* RTP handling */
3111

    
3112
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3113
                                       FFStream *stream, const char *session_id,
3114
                                       enum RTSPLowerTransport rtp_protocol)
3115
{
3116
    HTTPContext *c = NULL;
3117
    const char *proto_str;
3118

    
3119
    /* XXX: should output a warning page when coming
3120
       close to the connection limit */
3121
    if (nb_connections >= nb_max_connections)
3122
        goto fail;
3123

    
3124
    /* add a new connection */
3125
    c = av_mallocz(sizeof(HTTPContext));
3126
    if (!c)
3127
        goto fail;
3128

    
3129
    c->fd = -1;
3130
    c->poll_entry = NULL;
3131
    c->from_addr = *from_addr;
3132
    c->buffer_size = IOBUFFER_INIT_SIZE;
3133
    c->buffer = av_malloc(c->buffer_size);
3134
    if (!c->buffer)
3135
        goto fail;
3136
    nb_connections++;
3137
    c->stream = stream;
3138
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3139
    c->state = HTTPSTATE_READY;
3140
    c->is_packetized = 1;
3141
    c->rtp_protocol = rtp_protocol;
3142

    
3143
    /* protocol is shown in statistics */
3144
    switch(c->rtp_protocol) {
3145
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3146
        proto_str = "MCAST";
3147
        break;
3148
    case RTSP_LOWER_TRANSPORT_UDP:
3149
        proto_str = "UDP";
3150
        break;
3151
    case RTSP_LOWER_TRANSPORT_TCP:
3152
        proto_str = "TCP";
3153
        break;
3154
    default:
3155
        proto_str = "???";
3156
        break;
3157
    }
3158
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3159
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3160

    
3161
    current_bandwidth += stream->bandwidth;
3162

    
3163
    c->next = first_http_ctx;
3164
    first_http_ctx = c;
3165
    return c;
3166

    
3167
 fail:
3168
    if (c) {
3169
        av_free(c->buffer);
3170
        av_free(c);
3171
    }
3172
    return NULL;
3173
}
3174

    
3175
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3176
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3177
   used. */
3178
static int rtp_new_av_stream(HTTPContext *c,
3179
                             int stream_index, struct sockaddr_in *dest_addr,
3180
                             HTTPContext *rtsp_c)
3181
{
3182
    AVFormatContext *ctx;
3183
    AVStream *st;
3184
    char *ipaddr;
3185
    URLContext *h = NULL;
3186
    uint8_t *dummy_buf;
3187
    int max_packet_size;
3188

    
3189
    /* now we can open the relevant output stream */
3190
    ctx = avformat_alloc_context();
3191
    if (!ctx)
3192
        return -1;
3193
    ctx->oformat = guess_format("rtp", NULL, NULL);
3194

    
3195
    st = av_mallocz(sizeof(AVStream));
3196
    if (!st)
3197
        goto fail;
3198
    st->codec= avcodec_alloc_context();
3199
    ctx->nb_streams = 1;
3200
    ctx->streams[0] = st;
3201

    
3202
    if (!c->stream->feed ||
3203
        c->stream->feed == c->stream)
3204
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3205
    else
3206
        memcpy(st,
3207
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3208
               sizeof(AVStream));
3209
    st->priv_data = NULL;
3210

    
3211
    /* build destination RTP address */
3212
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3213

    
3214
    switch(c->rtp_protocol) {
3215
    case RTSP_LOWER_TRANSPORT_UDP:
3216
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3217
        /* RTP/UDP case */
3218

    
3219
        /* XXX: also pass as parameter to function ? */
3220
        if (c->stream->is_multicast) {
3221
            int ttl;
3222
            ttl = c->stream->multicast_ttl;
3223
            if (!ttl)
3224
                ttl = 16;
3225
            snprintf(ctx->filename, sizeof(ctx->filename),
3226
                     "rtp://%s:%d?multicast=1&ttl=%d",
3227
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3228
        } else {
3229
            snprintf(ctx->filename, sizeof(ctx->filename),
3230
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3231
        }
3232

    
3233
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3234
            goto fail;
3235
        c->rtp_handles[stream_index] = h;
3236
        max_packet_size = url_get_max_packet_size(h);
3237
        break;
3238
    case RTSP_LOWER_TRANSPORT_TCP:
3239
        /* RTP/TCP case */
3240
        c->rtsp_c = rtsp_c;
3241
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3242
        break;
3243
    default:
3244
        goto fail;
3245
    }
3246

    
3247
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3248
             ipaddr, ntohs(dest_addr->sin_port),
3249
             c->stream->filename, stream_index, c->protocol);
3250

    
3251
    /* normally, no packets should be output here, but the packet size may be checked */
3252
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3253
        /* XXX: close stream */
3254
        goto fail;
3255
    }
3256
    av_set_parameters(ctx, NULL);
3257
    if (av_write_header(ctx) < 0) {
3258
    fail:
3259
        if (h)
3260
            url_close(h);
3261
        av_free(ctx);
3262
        return -1;
3263
    }
3264
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3265
    av_free(dummy_buf);
3266

    
3267
    c->rtp_ctx[stream_index] = ctx;
3268
    return 0;
3269
}
3270

    
3271
/********************************************************************/
3272
/* ffserver initialization */
3273

    
3274
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3275
{
3276
    AVStream *fst;
3277

    
3278
    fst = av_mallocz(sizeof(AVStream));
3279
    if (!fst)
3280
        return NULL;
3281
    fst->codec= avcodec_alloc_context();
3282
    fst->priv_data = av_mallocz(sizeof(FeedData));
3283
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3284
    fst->index = stream->nb_streams;
3285
    av_set_pts_info(fst, 33, 1, 90000);
3286
    stream->streams[stream->nb_streams++] = fst;
3287
    return fst;
3288
}
3289

    
3290
/* return the stream number in the feed */
3291
static int add_av_stream(FFStream *feed, AVStream *st)
3292
{
3293
    AVStream *fst;
3294
    AVCodecContext *av, *av1;
3295
    int i;
3296

    
3297
    av = st->codec;
3298
    for(i=0;i<feed->nb_streams;i++) {
3299
        st = feed->streams[i];
3300
        av1 = st->codec;
3301
        if (av1->codec_id == av->codec_id &&
3302
            av1->codec_type == av->codec_type &&
3303
            av1->bit_rate == av->bit_rate) {
3304

    
3305
            switch(av->codec_type) {
3306
            case CODEC_TYPE_AUDIO:
3307
                if (av1->channels == av->channels &&
3308
                    av1->sample_rate == av->sample_rate)
3309
                    goto found;
3310
                break;
3311
            case CODEC_TYPE_VIDEO:
3312
                if (av1->width == av->width &&
3313
                    av1->height == av->height &&
3314
                    av1->time_base.den == av->time_base.den &&
3315
                    av1->time_base.num == av->time_base.num &&
3316
                    av1->gop_size == av->gop_size)
3317
                    goto found;
3318
                break;
3319
            default:
3320
                abort();
3321
            }
3322
        }
3323
    }
3324

    
3325
    fst = add_av_stream1(feed, av);
3326
    if (!fst)
3327
        return -1;
3328
    return feed->nb_streams - 1;
3329
 found:
3330
    return i;
3331
}
3332

    
3333
static void remove_stream(FFStream *stream)
3334
{
3335
    FFStream **ps;
3336
    ps = &first_stream;
3337
    while (*ps != NULL) {
3338
        if (*ps == stream)
3339
            *ps = (*ps)->next;
3340
        else
3341
            ps = &(*ps)->next;
3342
    }
3343
}
3344

    
3345
/* specific mpeg4 handling : we extract the raw parameters */
3346
static void extract_mpeg4_header(AVFormatContext *infile)
3347
{
3348
    int mpeg4_count, i, size;
3349
    AVPacket pkt;
3350
    AVStream *st;
3351
    const uint8_t *p;
3352

    
3353
    mpeg4_count = 0;
3354
    for(i=0;i<infile->nb_streams;i++) {
3355
        st = infile->streams[i];
3356
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3357
            st->codec->extradata_size == 0) {
3358
            mpeg4_count++;
3359
        }
3360
    }
3361
    if (!mpeg4_count)
3362
        return;
3363

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

    
3394
/* compute the needed AVStream for each file */
3395
static void build_file_streams(void)
3396
{
3397
    FFStream *stream, *stream_next;
3398
    AVFormatContext *infile;
3399
    int i, ret;
3400

    
3401
    /* gather all streams */
3402
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3403
        stream_next = stream->next;
3404
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3405
            !stream->feed) {
3406
            /* the stream comes from a file */
3407
            /* try to open the file */
3408
            /* open stream */
3409
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3410
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3411
                /* specific case : if transport stream output to RTP,
3412
                   we use a raw transport stream reader */
3413
                stream->ap_in->mpeg2ts_raw = 1;
3414
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3415
            }
3416

    
3417
            http_log("Opening file '%s'\n", stream->feed_filename);
3418
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3419
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3420
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3421
                /* remove stream (no need to spend more time on it) */
3422
            fail:
3423
                remove_stream(stream);
3424
            } else {
3425
                /* find all the AVStreams inside and reference them in
3426
                   'stream' */
3427
                if (av_find_stream_info(infile) < 0) {
3428
                    http_log("Could not find codec parameters from '%s'\n",
3429
                             stream->feed_filename);
3430
                    av_close_input_file(infile);
3431
                    goto fail;
3432
                }
3433
                extract_mpeg4_header(infile);
3434

    
3435
                for(i=0;i<infile->nb_streams;i++)
3436
                    add_av_stream1(stream, infile->streams[i]->codec);
3437

    
3438
                av_close_input_file(infile);
3439
            }
3440
        }
3441
    }
3442
}
3443

    
3444
/* compute the needed AVStream for each feed */
3445
static void build_feed_streams(void)
3446
{
3447
    FFStream *stream, *feed;
3448
    int i;
3449

    
3450
    /* gather all streams */
3451
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3452
        feed = stream->feed;
3453
        if (feed) {
3454
            if (!stream->is_feed) {
3455
                /* we handle a stream coming from a feed */
3456
                for(i=0;i<stream->nb_streams;i++)
3457
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3458
            }
3459
        }
3460
    }
3461

    
3462
    /* gather all streams */
3463
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3464
        feed = stream->feed;
3465
        if (feed) {
3466
            if (stream->is_feed) {
3467
                for(i=0;i<stream->nb_streams;i++)
3468
                    stream->feed_streams[i] = i;
3469
            }
3470
        }
3471
    }
3472

    
3473
    /* create feed files if needed */
3474
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3475
        int fd;
3476

    
3477
        if (url_exist(feed->feed_filename)) {
3478
            /* See if it matches */
3479
            AVFormatContext *s;
3480
            int matches = 0;
3481

    
3482
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3483
                /* Now see if it matches */
3484
                if (s->nb_streams == feed->nb_streams) {
3485
                    matches = 1;
3486
                    for(i=0;i<s->nb_streams;i++) {
3487
                        AVStream *sf, *ss;
3488
                        sf = feed->streams[i];
3489
                        ss = s->streams[i];
3490

    
3491
                        if (sf->index != ss->index ||
3492
                            sf->id != ss->id) {
3493
                            http_log("Index & Id do not match for stream %d (%s)\n",
3494
                                   i, feed->feed_filename);
3495
                            matches = 0;
3496
                        } else {
3497
                            AVCodecContext *ccf, *ccs;
3498

    
3499
                            ccf = sf->codec;
3500
                            ccs = ss->codec;
3501
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3502

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

    
3536
                av_close_input_file(s);
3537
            } else
3538
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3539
                        feed->feed_filename);
3540

    
3541
            if (!matches) {
3542
                if (feed->readonly) {
3543
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3544
                        feed->feed_filename);
3545
                    exit(1);
3546
                }
3547
                unlink(feed->feed_filename);
3548
            }
3549
        }
3550
        if (!url_exist(feed->feed_filename)) {
3551
            AVFormatContext s1 = {0}, *s = &s1;
3552

    
3553
            if (feed->readonly) {
3554
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3555
                    feed->feed_filename);
3556
                exit(1);
3557
            }
3558

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

    
3589
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3590
        feed->feed_size = lseek(fd, 0, SEEK_END);
3591
        /* ensure that we do not wrap before the end of file */
3592
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3593
            feed->feed_max_size = feed->feed_size;
3594

    
3595
        close(fd);
3596
    }
3597
}
3598

    
3599
/* compute the bandwidth used by each stream */
3600
static void compute_bandwidth(void)
3601
{
3602
    unsigned bandwidth;
3603
    int i;
3604
    FFStream *stream;
3605

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

    
3623
static void get_arg(char *buf, int buf_size, const char **pp)
3624
{
3625
    const char *p;
3626
    char *q;
3627
    int quote;
3628

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

    
3655
/* add a codec and set the default parameters */
3656
static void add_codec(FFStream *stream, AVCodecContext *av)
3657
{
3658
    AVStream *st;
3659

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

    
3694
        if (!av->nsse_weight)
3695
            av->nsse_weight = 8;
3696

    
3697
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3698
        av->me_method = ME_EPZS;
3699
        av->rc_buffer_aggressivity = 1.0;
3700

    
3701
        if (!av->rc_eq)
3702
            av->rc_eq = "tex^qComp";
3703
        if (!av->i_quant_factor)
3704
            av->i_quant_factor = -0.8;
3705
        if (!av->b_quant_factor)
3706
            av->b_quant_factor = 1.25;
3707
        if (!av->b_quant_offset)
3708
            av->b_quant_offset = 1.25;
3709
        if (!av->rc_max_rate)
3710
            av->rc_max_rate = av->bit_rate * 2;
3711

    
3712
        if (av->rc_max_rate && !av->rc_buffer_size) {
3713
            av->rc_buffer_size = av->rc_max_rate;
3714
        }
3715

    
3716

    
3717
        break;
3718
    default:
3719
        abort();
3720
    }
3721

    
3722
    st = av_mallocz(sizeof(AVStream));
3723
    if (!st)
3724
        return;
3725
    st->codec = avcodec_alloc_context();
3726
    stream->streams[stream->nb_streams++] = st;
3727
    memcpy(st->codec, av, sizeof(AVCodecContext));
3728
}
3729

    
3730
static enum CodecID opt_audio_codec(const char *arg)
3731
{
3732
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3733

    
3734
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3735
        return CODEC_ID_NONE;
3736

    
3737
    return p->id;
3738
}
3739

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

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

    
3747
    return p->id;
3748
}
3749

    
3750
/* simplistic plugin support */
3751

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

    
3764
    init_func = dlsym(dll, "ffserver_module_init");
3765
    if (!init_func) {
3766
        fprintf(stderr,
3767
                "%s: init function 'ffserver_module_init()' not found\n",
3768
                filename);
3769
        dlclose(dll);
3770
    }
3771

    
3772
    init_func();
3773
}
3774
#endif
3775

    
3776
static int ffserver_opt_default(const char *opt, const char *arg,
3777
                       AVCodecContext *avctx, int type)
3778
{
3779
    int ret = 0;
3780
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3781
    if(o)
3782
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3783
    return ret;
3784
}
3785

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

    
3799
    f = fopen(filename, "r");
3800
    if (!f) {
3801
        perror(filename);
3802
        return -1;
3803
    }
3804

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

    
3826
        get_arg(cmd, sizeof(cmd), &p);
3827

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

    
3908
                for (s = first_feed; s; s = s->next) {
3909
                    if (!strcmp(feed->filename, s->filename)) {
3910
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3911
                                filename, line_num, s->filename);
3912
                        errors++;
3913
                    }
3914
                }
3915

    
3916
                feed->fmt = guess_format("ffm", NULL, NULL);
3917
                /* defaut feed file */
3918
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3919
                         "/tmp/%s.ffm", feed->filename);
3920
                feed->feed_max_size = 5 * 1024 * 1024;
3921
                feed->is_feed = 1;
3922
                feed->feed = feed; /* self feeding :-) */
3923

    
3924
                /* add in stream list */
3925
                *last_stream = feed;
3926
                last_stream = &feed->next;
3927
                /* add in feed list */
3928
                *last_feed = feed;
3929
                last_feed = &feed->next_feed;
3930
            }
3931
        } else if (!strcasecmp(cmd, "Launch")) {
3932
            if (feed) {
3933
                int i;
3934

    
3935
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3936

    
3937
                for (i = 0; i < 62; i++) {
3938
                    get_arg(arg, sizeof(arg), &p);
3939
                    if (!arg[0])
3940
                        break;
3941

    
3942
                    feed->child_argv[i] = av_strdup(arg);
3943
                }
3944

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

    
3947
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3948
                    "http://%s:%d/%s",
3949
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3950
                    inet_ntoa(my_http_addr.sin_addr),
3951
                    ntohs(my_http_addr.sin_port), feed->filename);
3952
            }
3953
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3954
            if (feed) {
3955
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3956
                feed->readonly = 1;
3957
            } else if (stream) {
3958
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3959
            }
3960
        } else if (!strcasecmp(cmd, "File")) {
3961
            if (feed) {
3962
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3963
            } else if (stream)
3964
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3965
        } else if (!strcasecmp(cmd, "Truncate")) {
3966
            if (feed) {
3967
                get_arg(arg, sizeof(arg), &p);
3968
                feed->truncate = strtod(arg, NULL);
3969
            }
3970
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3971
            if (feed) {
3972
                char *p1;
3973
                double fsize;
3974

    
3975
                get_arg(arg, sizeof(arg), &p);
3976
                p1 = arg;
3977
                fsize = strtod(p1, &p1);
3978
                switch(toupper(*p1)) {
3979
                case 'K':
3980
                    fsize *= 1024;
3981
                    break;
3982
                case 'M':
3983
                    fsize *= 1024 * 1024;
3984
                    break;
3985
                case 'G':
3986
                    fsize *= 1024 * 1024 * 1024;
3987
                    break;
3988
                }
3989
                feed->feed_max_size = (int64_t)fsize;
3990
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
3991
                    fprintf(stderr, "%s:%d: Feed max file size is too small, "
3992
                            "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
3993
                    errors++;
3994
                }
3995
            }
3996
        } else if (!strcasecmp(cmd, "</Feed>")) {
3997
            if (!feed) {
3998
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3999
                        filename, line_num);
4000
                errors++;
4001
            }
4002
            feed = NULL;
4003
        } else if (!strcasecmp(cmd, "<Stream")) {
4004
            /*********************************************/
4005
            /* Stream related options */
4006
            char *q;
4007
            if (stream || feed) {
4008
                fprintf(stderr, "%s:%d: Already in a tag\n",
4009
                        filename, line_num);
4010
            } else {
4011
                FFStream *s;
4012
                const AVClass *class;
4013
                stream = av_mallocz(sizeof(FFStream));
4014
                get_arg(stream->filename, sizeof(stream->filename), &p);
4015
                q = strrchr(stream->filename, '>');
4016
                if (*q)
4017
                    *q = '\0';
4018

    
4019
                for (s = first_stream; s; s = s->next) {
4020
                    if (!strcmp(stream->filename, s->filename)) {
4021
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
4022
                                filename, line_num, s->filename);
4023
                        errors++;
4024
                    }
4025
                }
4026

    
4027
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
4028
                /* fetch avclass so AVOption works
4029
                 * FIXME try to use avcodec_get_context_defaults2
4030
                 * without changing defaults too much */
4031
                avcodec_get_context_defaults(&video_enc);
4032
                class = video_enc.av_class;
4033
                memset(&audio_enc, 0, sizeof(AVCodecContext));
4034
                memset(&video_enc, 0, sizeof(AVCodecContext));
4035
                audio_enc.av_class = class;
4036
                video_enc.av_class = class;
4037
                audio_id = CODEC_ID_NONE;
4038
                video_id = CODEC_ID_NONE;
4039
                if (stream->fmt) {
4040
                    audio_id = stream->fmt->audio_codec;
4041
                    video_id = stream->fmt->video_codec;
4042
                }
4043

    
4044
                *last_stream = stream;
4045
                last_stream = &stream->next;
4046
            }
4047
        } else if (!strcasecmp(cmd, "Feed")) {
4048
            get_arg(arg, sizeof(arg), &p);
4049
            if (stream) {
4050
                FFStream *sfeed;
4051

    
4052
                sfeed = first_feed;
4053
                while (sfeed != NULL) {
4054
                    if (!strcmp(sfeed->filename, arg))
4055
                        break;
4056
                    sfeed = sfeed->next_feed;
4057
                }
4058
                if (!sfeed)
4059
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4060
                            filename, line_num, arg);
4061
                else
4062
                    stream->feed = sfeed;
4063
            }
4064
        } else if (!strcasecmp(cmd, "Format")) {
4065
            get_arg(arg, sizeof(arg), &p);
4066
            if (stream) {
4067
                if (!strcmp(arg, "status")) {
4068
                    stream->stream_type = STREAM_TYPE_STATUS;
4069
                    stream->fmt = NULL;
4070
                } else {
4071
                    stream->stream_type = STREAM_TYPE_LIVE;
4072
                    /* jpeg cannot be used here, so use single frame jpeg */
4073
                    if (!strcmp(arg, "jpeg"))
4074
                        strcpy(arg, "mjpeg");
4075
                    stream->fmt = guess_stream_format(arg, NULL, NULL);
4076
                    if (!stream->fmt) {
4077
                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4078
                                filename, line_num, arg);
4079
                        errors++;
4080
                    }
4081
                }
4082
                if (stream->fmt) {
4083
                    audio_id = stream->fmt->audio_codec;
4084
                    video_id = stream->fmt->video_codec;
4085
                }
4086
            }
4087
        } else if (!strcasecmp(cmd, "InputFormat")) {
4088
            get_arg(arg, sizeof(arg), &p);
4089
            if (stream) {
4090
                stream->ifmt = av_find_input_format(arg);
4091
                if (!stream->ifmt) {
4092
                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4093
                            filename, line_num, arg);
4094
                }
4095
            }
4096
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4097
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4098
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4099
            } else {
4100
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4101
                            filename, line_num);
4102
                errors++;
4103
            }
4104
        } else if (!strcasecmp(cmd, "Author")) {
4105
            if (stream)
4106
                get_arg(stream->author, sizeof(stream->author), &p);
4107
        } else if (!strcasecmp(cmd, "Comment")) {
4108
            if (stream)
4109
                get_arg(stream->comment, sizeof(stream->comment), &p);
4110
        } else if (!strcasecmp(cmd, "Copyright")) {
4111
            if (stream)
4112
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4113
        } else if (!strcasecmp(cmd, "Title")) {
4114
            if (stream)
4115
                get_arg(stream->title, sizeof(stream->title), &p);
4116
        } else if (!strcasecmp(cmd, "Preroll")) {
4117
            get_arg(arg, sizeof(arg), &p);
4118
            if (stream)
4119
                stream->prebuffer = atof(arg) * 1000;
4120
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4121
            if (stream)
4122
                stream->send_on_key = 1;
4123
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4124
            get_arg(arg, sizeof(arg), &p);
4125
            audio_id = opt_audio_codec(arg);
4126
            if (audio_id == CODEC_ID_NONE) {
4127
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4128
                        filename, line_num, arg);
4129
                errors++;
4130
            }
4131
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4132
            get_arg(arg, sizeof(arg), &p);
4133
            video_id = opt_video_codec(arg);
4134
            if (video_id == CODEC_ID_NONE) {
4135
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4136
                        filename, line_num, arg);
4137
                errors++;
4138
            }
4139
        } else if (!strcasecmp(cmd, "MaxTime")) {
4140
            get_arg(arg, sizeof(arg), &p);
4141
            if (stream)
4142
                stream->max_time = atof(arg) * 1000;
4143
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4144
            get_arg(arg, sizeof(arg), &p);
4145
            if (stream)
4146
                audio_enc.bit_rate = atoi(arg) * 1000;
4147
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4148
            get_arg(arg, sizeof(arg), &p);
4149
            if (stream)
4150
                audio_enc.channels = atoi(arg);
4151
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4152
            get_arg(arg, sizeof(arg), &p);
4153
            if (stream)
4154
                audio_enc.sample_rate = atoi(arg);
4155
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4156
            get_arg(arg, sizeof(arg), &p);
4157
            if (stream) {
4158
//                audio_enc.quality = atof(arg) * 1000;
4159
            }
4160
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4161
            if (stream) {
4162
                int minrate, maxrate;
4163

    
4164
                get_arg(arg, sizeof(arg), &p);
4165

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

    
4328
            get_arg(arg, sizeof(arg), &p);
4329
            if (strcasecmp(arg, "allow") == 0)
4330
                acl.action = IP_ALLOW;
4331
            else if (strcasecmp(arg, "deny") == 0)
4332
                acl.action = IP_DENY;
4333
            else {
4334
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4335
                        filename, line_num, arg);
4336
                errors++;
4337
            }
4338

    
4339
            get_arg(arg, sizeof(arg), &p);
4340

    
4341
            if (resolve_host(&acl.first, arg) != 0) {
4342
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4343
                        filename, line_num, arg);
4344
                errors++;
4345
            } else
4346
                acl.last = acl.first;
4347

    
4348
            get_arg(arg, sizeof(arg), &p);
4349

    
4350
            if (arg[0]) {
4351
                if (resolve_host(&acl.last, arg) != 0) {
4352
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4353
                            filename, line_num, arg);
4354
                    errors++;
4355
                }
4356
            }
4357

    
4358
            if (!errors) {
4359
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4360
                IPAddressACL **naclp = 0;
4361

    
4362
                acl.next = 0;
4363
                *nacl = acl;
4364

    
4365
                if (stream)
4366
                    naclp = &stream->acl;
4367
                else if (feed)
4368
                    naclp = &feed->acl;
4369
                else {
4370
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4371
                            filename, line_num);
4372
                    errors++;
4373
                }
4374

    
4375
                if (naclp) {
4376
                    while (*naclp)
4377
                        naclp = &(*naclp)->next;
4378

    
4379
                    *naclp = nacl;
4380
                }
4381
            }
4382
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4383
            get_arg(arg, sizeof(arg), &p);
4384
            if (stream) {
4385
                av_freep(&stream->rtsp_option);
4386
                stream->rtsp_option = av_strdup(arg);
4387
            }
4388
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4389
            get_arg(arg, sizeof(arg), &p);
4390
            if (stream) {
4391
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4392
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4393
                            filename, line_num, arg);
4394
                    errors++;
4395
                }
4396
                stream->is_multicast = 1;
4397
                stream->loop = 1; /* default is looping */
4398
            }
4399
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4400
            get_arg(arg, sizeof(arg), &p);
4401
            if (stream)
4402
                stream->multicast_port = atoi(arg);
4403
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4404
            get_arg(arg, sizeof(arg), &p);
4405
            if (stream)
4406
                stream->multicast_ttl = atoi(arg);
4407
        } else if (!strcasecmp(cmd, "NoLoop")) {
4408
            if (stream)
4409
                stream->loop = 0;
4410
        } else if (!strcasecmp(cmd, "</Stream>")) {
4411
            if (!stream) {
4412
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4413
                        filename, line_num);
4414
                errors++;
4415
            } else {
4416
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4417
                    if (audio_id != CODEC_ID_NONE) {
4418
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4419
                        audio_enc.codec_id = audio_id;
4420
                        add_codec(stream, &audio_enc);
4421
                    }
4422
                    if (video_id != CODEC_ID_NONE) {
4423
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4424
                        video_enc.codec_id = video_id;
4425
                        add_codec(stream, &video_enc);
4426
                    }
4427
                }
4428
                stream = NULL;
4429
            }
4430
        } else if (!strcasecmp(cmd, "<Redirect")) {
4431
            /*********************************************/
4432
            char *q;
4433
            if (stream || feed || redirect) {
4434
                fprintf(stderr, "%s:%d: Already in a tag\n",
4435
                        filename, line_num);
4436
                errors++;
4437
            } else {
4438
                redirect = av_mallocz(sizeof(FFStream));
4439
                *last_stream = redirect;
4440
                last_stream = &redirect->next;
4441

    
4442
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4443
                q = strrchr(redirect->filename, '>');
4444
                if (*q)
4445
                    *q = '\0';
4446
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4447
            }
4448
        } else if (!strcasecmp(cmd, "URL")) {
4449
            if (redirect)
4450
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4451
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4452
            if (!redirect) {
4453
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4454
                        filename, line_num);
4455
                errors++;
4456
            } else {
4457
                if (!redirect->feed_filename[0]) {
4458
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4459
                            filename, line_num);
4460
                    errors++;
4461
                }
4462
                redirect = NULL;
4463
            }
4464
        } else if (!strcasecmp(cmd, "LoadModule")) {
4465
            get_arg(arg, sizeof(arg), &p);
4466
#if HAVE_DLOPEN
4467
            load_module(arg);
4468
#else
4469
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4470
                    filename, line_num, arg);
4471
            errors++;
4472
#endif
4473
        } else {
4474
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4475
                    filename, line_num, cmd);
4476
        }
4477
    }
4478

    
4479
    fclose(f);
4480
    if (errors)
4481
        return -1;
4482
    else
4483
        return 0;
4484
}
4485

    
4486
static void handle_child_exit(int sig)
4487
{
4488
    pid_t pid;
4489
    int status;
4490

    
4491
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4492
        FFStream *feed;
4493

    
4494
        for (feed = first_feed; feed; feed = feed->next) {
4495
            if (feed->pid == pid) {
4496
                int uptime = time(0) - feed->pid_start;
4497

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

    
4501
                if (uptime < 30)
4502
                    /* Turn off any more restarts */
4503
                    feed->child_argv = 0;
4504
            }
4505
        }
4506
    }
4507

    
4508
    need_to_start_children = 1;
4509
}
4510

    
4511
static void opt_debug(void)
4512
{
4513
    ffserver_debug = 1;
4514
    ffserver_daemon = 0;
4515
    logfilename[0] = '-';
4516
}
4517

    
4518
static void opt_show_help(void)
4519
{
4520
    printf("usage: ffserver [options]\n"
4521
           "Hyper fast multi format Audio/Video streaming server\n");
4522
    printf("\n");
4523
    show_help_options(options, "Main options:\n", 0, 0);
4524
}
4525

    
4526
static const OptionDef options[] = {
4527
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4528
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4529
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4530
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4531
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4532
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4533
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4534
    { NULL },
4535
};
4536

    
4537
int main(int argc, char **argv)
4538
{
4539
    struct sigaction sigact;
4540

    
4541
    av_register_all();
4542

    
4543
    show_banner();
4544

    
4545
    config_filename = "/etc/ffserver.conf";
4546

    
4547
    my_program_name = argv[0];
4548
    my_program_dir = getcwd(0, 0);
4549
    ffserver_daemon = 1;
4550

    
4551
    parse_options(argc, argv, options, NULL);
4552

    
4553
    unsetenv("http_proxy");             /* Kill the http_proxy */
4554

    
4555
    av_lfg_init(&random_state, ff_random_get_seed());
4556

    
4557
    memset(&sigact, 0, sizeof(sigact));
4558
    sigact.sa_handler = handle_child_exit;
4559
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4560
    sigaction(SIGCHLD, &sigact, 0);
4561

    
4562
    if (parse_ffconfig(config_filename) < 0) {
4563
        fprintf(stderr, "Incorrect config file - exiting.\n");
4564
        exit(1);
4565
    }
4566

    
4567
    /* open log file if needed */
4568
    if (logfilename[0] != '\0') {
4569
        if (!strcmp(logfilename, "-"))
4570
            logfile = stdout;
4571
        else
4572
            logfile = fopen(logfilename, "a");
4573
        av_log_set_callback(http_av_log);
4574
    }
4575

    
4576
    build_file_streams();
4577

    
4578
    build_feed_streams();
4579

    
4580
    compute_bandwidth();
4581

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

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

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

    
4610
    if (ffserver_daemon)
4611
        chdir("/");
4612

    
4613
    if (http_server() < 0) {
4614
        http_log("Could not start server\n");
4615
        exit(1);
4616
    }
4617

    
4618
    return 0;
4619
}