Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 19c8c4ec

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
    int chunked_encoding;
128
    int chunk_size;               /* 0 if it needs to be read */
129
    struct HTTPContext *next;
130
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
131
    int64_t data_count;
132
    /* feed input */
133
    int feed_fd;
134
    /* input format handling */
135
    AVFormatContext *fmt_in;
136
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
137
    int64_t first_pts;            /* initial pts value */
138
    int64_t cur_pts;             /* current pts value from the stream in us */
139
    int64_t cur_frame_duration;  /* duration of the current frame in us */
140
    int cur_frame_bytes;       /* output frame size, needed to compute
141
                                  the time at which we send each
142
                                  packet */
143
    int pts_stream_index;        /* stream we choose as clock reference */
144
    int64_t cur_clock;           /* current clock reference value in us */
145
    /* output format handling */
146
    struct FFStream *stream;
147
    /* -1 is invalid stream */
148
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
149
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
150
    int switch_pending;
151
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
152
    int last_packet_sent; /* true if last data packet was sent */
153
    int suppress_log;
154
    DataRateData datarate;
155
    int wmp_client_id;
156
    char protocol[16];
157
    char method[16];
158
    char url[128];
159
    int buffer_size;
160
    uint8_t *buffer;
161
    int is_packetized; /* if true, the stream is packetized */
162
    int packet_stream_index; /* current stream for output in state machine */
163

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

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

    
174
    /* RTP/UDP specific */
175
    URLContext *rtp_handles[MAX_STREAMS];
176

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

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

    
189
enum IPAddressAction {
190
    IP_ALLOW = 1,
191
    IP_DENY,
192
};
193

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

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

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

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

    
256
static struct sockaddr_in my_http_addr;
257
static struct sockaddr_in my_rtsp_addr;
258

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

    
264
static void new_connection(int server_fd, int is_rtsp);
265
static void close_connection(HTTPContext *c);
266

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

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

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

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

    
297
static const char *my_program_name;
298
static const char *my_program_dir;
299

    
300
static const char *config_filename;
301
static int ffserver_debug;
302
static int ffserver_daemon;
303
static int no_launch;
304
static int need_to_start_children;
305

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

    
311
static uint64_t max_bandwidth = 1000;
312
static uint64_t current_bandwidth;
313

    
314
static int64_t cur_time;           // Making this global saves on passing it around everywhere
315

    
316
static AVLFG random_state;
317

    
318
static FILE *logfile = NULL;
319

    
320
static char *ctime1(char *buf2)
321
{
322
    time_t ti;
323
    char *p;
324

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

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

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

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

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

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

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

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

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

    
401

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

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

    
411
            feed->pid = fork();
412

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

    
423
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
424

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

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

    
438
                for (i = 3; i < 256; i++)
439
                    close(i);
440

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

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

    
454
                signal(SIGPIPE, SIG_DFL);
455

    
456
                execvp(pathname, feed->child_argv);
457

    
458
                _exit(1);
459
            }
460
        }
461
    }
462
}
463

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

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

    
475
    tmp = 1;
476
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
477

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

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

    
493
    return server_fd;
494
}
495

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

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

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

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

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

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

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

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

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

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

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

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

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

    
581
    http_log("FFserver started.\n");
582

    
583
    start_children(first_feed);
584

    
585
    start_multicast();
586

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

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

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

    
659
        cur_time = av_gettime() / 1000;
660

    
661
        if (need_to_start_children) {
662
            need_to_start_children = 0;
663
            start_children(first_feed);
664
        }
665

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

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

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

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

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

    
721

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

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

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

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

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

    
755
    c->next = first_http_ctx;
756
    first_http_ctx = c;
757
    nb_connections++;
758

    
759
    start_wait_request(c, is_rtsp);
760

    
761
    return;
762

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

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

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

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

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

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

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

    
824
    ctx = &c->fmt_ctx;
825

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

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

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

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

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

    
856
static int handle_connection(HTTPContext *c)
857
{
858
    int len, ret;
859

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

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

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

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

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

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

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

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

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

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

    
1041
            while (*q && *q != '\n' && isspace(*q))
1042
                q++;
1043

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

    
1048
                q += 20;
1049

    
1050
                memset(rates, 0xff, ratelen);
1051

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

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

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

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

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

    
1074
        p++;
1075
    }
1076

    
1077
    return 0;
1078
}
1079

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

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

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

    
1095
        /* Potential stream */
1096

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

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

    
1114
    return best;
1115
}
1116

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

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

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

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

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

    
1152
    return action_required;
1153
}
1154

    
1155

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

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

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

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

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

    
1197
static void get_arg(char *buf, int buf_size, const char **pp)
1198
{
1199
    const char *p;
1200
    char *q;
1201
    int quote;
1202

    
1203
    p = *pp;
1204
    while (isspace(*p)) p++;
1205
    q = buf;
1206
    quote = 0;
1207
    if (*p == '\"' || *p == '\'')
1208
        quote = *p++;
1209
    for(;;) {
1210
        if (quote) {
1211
            if (*p == quote)
1212
                break;
1213
        } else {
1214
            if (isspace(*p))
1215
                break;
1216
        }
1217
        if (*p == '\0')
1218
            break;
1219
        if ((q - buf) < buf_size - 1)
1220
            *q++ = *p;
1221
        p++;
1222
    }
1223
    *q = '\0';
1224
    if (quote && *p == quote)
1225
        p++;
1226
    *pp = p;
1227
}
1228

    
1229
static int validate_acl(FFStream *stream, HTTPContext *c)
1230
{
1231
    enum IPAddressAction last_action = IP_DENY;
1232
    IPAddressACL *acl;
1233
    struct in_addr *src = &c->from_addr.sin_addr;
1234
    unsigned long src_addr = src->s_addr;
1235

    
1236
    for (acl = stream->acl; acl; acl = acl->next) {
1237
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1238
            return (acl->action == IP_ALLOW) ? 1 : 0;
1239
        last_action = acl->action;
1240
    }
1241

    
1242
    /* Nothing matched, so return not the last action */
1243
    return (last_action == IP_DENY) ? 1 : 0;
1244
}
1245

    
1246
/* compute the real filename of a file by matching it without its
1247
   extensions to all the stream filenames */
1248
static void compute_real_filename(char *filename, int max_size)
1249
{
1250
    char file1[1024];
1251
    char file2[1024];
1252
    char *p;
1253
    FFStream *stream;
1254

    
1255
    /* compute filename by matching without the file extensions */
1256
    av_strlcpy(file1, filename, sizeof(file1));
1257
    p = strrchr(file1, '.');
1258
    if (p)
1259
        *p = '\0';
1260
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1261
        av_strlcpy(file2, stream->filename, sizeof(file2));
1262
        p = strrchr(file2, '.');
1263
        if (p)
1264
            *p = '\0';
1265
        if (!strcmp(file1, file2)) {
1266
            av_strlcpy(filename, stream->filename, max_size);
1267
            break;
1268
        }
1269
    }
1270
}
1271

    
1272
enum RedirType {
1273
    REDIR_NONE,
1274
    REDIR_ASX,
1275
    REDIR_RAM,
1276
    REDIR_ASF,
1277
    REDIR_RTSP,
1278
    REDIR_SDP,
1279
};
1280

    
1281
/* parse http request and prepare header */
1282
static int http_parse_request(HTTPContext *c)
1283
{
1284
    char *p;
1285
    enum RedirType redir_type;
1286
    char cmd[32];
1287
    char info[1024], filename[1024];
1288
    char url[1024], *q;
1289
    char protocol[32];
1290
    char msg[1024];
1291
    const char *mime_type;
1292
    FFStream *stream;
1293
    int i;
1294
    char ratebuf[32];
1295
    char *useragent = 0;
1296

    
1297
    p = c->buffer;
1298
    get_word(cmd, sizeof(cmd), (const char **)&p);
1299
    av_strlcpy(c->method, cmd, sizeof(c->method));
1300

    
1301
    if (!strcmp(cmd, "GET"))
1302
        c->post = 0;
1303
    else if (!strcmp(cmd, "POST"))
1304
        c->post = 1;
1305
    else
1306
        return -1;
1307

    
1308
    get_word(url, sizeof(url), (const char **)&p);
1309
    av_strlcpy(c->url, url, sizeof(c->url));
1310

    
1311
    get_word(protocol, sizeof(protocol), (const char **)&p);
1312
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1313
        return -1;
1314

    
1315
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1316

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

    
1320
    /* find the filename and the optional info string in the request */
1321
    p = strchr(url, '?');
1322
    if (p) {
1323
        av_strlcpy(info, p, sizeof(info));
1324
        *p = '\0';
1325
    } else
1326
        info[0] = '\0';
1327

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

    
1330
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1331
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1332
            useragent = p + 11;
1333
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1334
                useragent++;
1335
            break;
1336
        }
1337
        p = strchr(p, '\n');
1338
        if (!p)
1339
            break;
1340

    
1341
        p++;
1342
    }
1343

    
1344
    redir_type = REDIR_NONE;
1345
    if (av_match_ext(filename, "asx")) {
1346
        redir_type = REDIR_ASX;
1347
        filename[strlen(filename)-1] = 'f';
1348
    } else if (av_match_ext(filename, "asf") &&
1349
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1350
        /* if this isn't WMP or lookalike, return the redirector file */
1351
        redir_type = REDIR_ASF;
1352
    } else if (av_match_ext(filename, "rpm,ram")) {
1353
        redir_type = REDIR_RAM;
1354
        strcpy(filename + strlen(filename)-2, "m");
1355
    } else if (av_match_ext(filename, "rtsp")) {
1356
        redir_type = REDIR_RTSP;
1357
        compute_real_filename(filename, sizeof(filename) - 1);
1358
    } else if (av_match_ext(filename, "sdp")) {
1359
        redir_type = REDIR_SDP;
1360
        compute_real_filename(filename, sizeof(filename) - 1);
1361
    }
1362

    
1363
    // "redirect" / request to index.html
1364
    if (!strlen(filename))
1365
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1366

    
1367
    stream = first_stream;
1368
    while (stream != NULL) {
1369
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1370
            break;
1371
        stream = stream->next;
1372
    }
1373
    if (stream == NULL) {
1374
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1375
        http_log("File '%s' not found\n", url);
1376
        goto send_error;
1377
    }
1378

    
1379
    c->stream = stream;
1380
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1381
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1382

    
1383
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1384
        c->http_error = 301;
1385
        q = c->buffer;
1386
        q += snprintf(q, c->buffer_size,
1387
                      "HTTP/1.0 301 Moved\r\n"
1388
                      "Location: %s\r\n"
1389
                      "Content-type: text/html\r\n"
1390
                      "\r\n"
1391
                      "<html><head><title>Moved</title></head><body>\r\n"
1392
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1393
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1394
        /* prepare output buffer */
1395
        c->buffer_ptr = c->buffer;
1396
        c->buffer_end = q;
1397
        c->state = HTTPSTATE_SEND_HEADER;
1398
        return 0;
1399
    }
1400

    
1401
    /* If this is WMP, get the rate information */
1402
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1403
        if (modify_current_stream(c, ratebuf)) {
1404
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1405
                if (c->switch_feed_streams[i] >= 0)
1406
                    do_switch_stream(c, i);
1407
            }
1408
        }
1409
    }
1410

    
1411
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1412
        current_bandwidth += stream->bandwidth;
1413

    
1414
    /* If already streaming this feed, do not let start another feeder. */
1415
    if (stream->feed_opened) {
1416
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1417
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1418
        goto send_error;
1419
    }
1420

    
1421
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1422
        c->http_error = 200;
1423
        q = c->buffer;
1424
        q += snprintf(q, c->buffer_size,
1425
                      "HTTP/1.0 200 Server too busy\r\n"
1426
                      "Content-type: text/html\r\n"
1427
                      "\r\n"
1428
                      "<html><head><title>Too busy</title></head><body>\r\n"
1429
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1430
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1431
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1432
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1433
        /* prepare output buffer */
1434
        c->buffer_ptr = c->buffer;
1435
        c->buffer_end = q;
1436
        c->state = HTTPSTATE_SEND_HEADER;
1437
        return 0;
1438
    }
1439

    
1440
    if (redir_type != REDIR_NONE) {
1441
        char *hostinfo = 0;
1442

    
1443
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1444
            if (strncasecmp(p, "Host:", 5) == 0) {
1445
                hostinfo = p + 5;
1446
                break;
1447
            }
1448
            p = strchr(p, '\n');
1449
            if (!p)
1450
                break;
1451

    
1452
            p++;
1453
        }
1454

    
1455
        if (hostinfo) {
1456
            char *eoh;
1457
            char hostbuf[260];
1458

    
1459
            while (isspace(*hostinfo))
1460
                hostinfo++;
1461

    
1462
            eoh = strchr(hostinfo, '\n');
1463
            if (eoh) {
1464
                if (eoh[-1] == '\r')
1465
                    eoh--;
1466

    
1467
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1468
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1469
                    hostbuf[eoh - hostinfo] = 0;
1470

    
1471
                    c->http_error = 200;
1472
                    q = c->buffer;
1473
                    switch(redir_type) {
1474
                    case REDIR_ASX:
1475
                        q += snprintf(q, c->buffer_size,
1476
                                      "HTTP/1.0 200 ASX Follows\r\n"
1477
                                      "Content-type: video/x-ms-asf\r\n"
1478
                                      "\r\n"
1479
                                      "<ASX Version=\"3\">\r\n"
1480
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1481
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1482
                                      "</ASX>\r\n", hostbuf, filename, info);
1483
                        break;
1484
                    case REDIR_RAM:
1485
                        q += snprintf(q, c->buffer_size,
1486
                                      "HTTP/1.0 200 RAM Follows\r\n"
1487
                                      "Content-type: audio/x-pn-realaudio\r\n"
1488
                                      "\r\n"
1489
                                      "# Autogenerated by ffserver\r\n"
1490
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1491
                        break;
1492
                    case REDIR_ASF:
1493
                        q += snprintf(q, c->buffer_size,
1494
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1495
                                      "Content-type: video/x-ms-asf\r\n"
1496
                                      "\r\n"
1497
                                      "[Reference]\r\n"
1498
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1499
                        break;
1500
                    case REDIR_RTSP:
1501
                        {
1502
                            char hostname[256], *p;
1503
                            /* extract only hostname */
1504
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1505
                            p = strrchr(hostname, ':');
1506
                            if (p)
1507
                                *p = '\0';
1508
                            q += snprintf(q, c->buffer_size,
1509
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1510
                                          /* XXX: incorrect mime type ? */
1511
                                          "Content-type: application/x-rtsp\r\n"
1512
                                          "\r\n"
1513
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1514
                        }
1515
                        break;
1516
                    case REDIR_SDP:
1517
                        {
1518
                            uint8_t *sdp_data;
1519
                            int sdp_data_size, len;
1520
                            struct sockaddr_in my_addr;
1521

    
1522
                            q += snprintf(q, c->buffer_size,
1523
                                          "HTTP/1.0 200 OK\r\n"
1524
                                          "Content-type: application/sdp\r\n"
1525
                                          "\r\n");
1526

    
1527
                            len = sizeof(my_addr);
1528
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1529

    
1530
                            /* XXX: should use a dynamic buffer */
1531
                            sdp_data_size = prepare_sdp_description(stream,
1532
                                                                    &sdp_data,
1533
                                                                    my_addr.sin_addr);
1534
                            if (sdp_data_size > 0) {
1535
                                memcpy(q, sdp_data, sdp_data_size);
1536
                                q += sdp_data_size;
1537
                                *q = '\0';
1538
                                av_free(sdp_data);
1539
                            }
1540
                        }
1541
                        break;
1542
                    default:
1543
                        abort();
1544
                        break;
1545
                    }
1546

    
1547
                    /* prepare output buffer */
1548
                    c->buffer_ptr = c->buffer;
1549
                    c->buffer_end = q;
1550
                    c->state = HTTPSTATE_SEND_HEADER;
1551
                    return 0;
1552
                }
1553
            }
1554
        }
1555

    
1556
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1557
        goto send_error;
1558
    }
1559

    
1560
    stream->conns_served++;
1561

    
1562
    /* XXX: add there authenticate and IP match */
1563

    
1564
    if (c->post) {
1565
        /* if post, it means a feed is being sent */
1566
        if (!stream->is_feed) {
1567
            /* However it might be a status report from WMP! Let us log the
1568
             * data as it might come in handy one day. */
1569
            char *logline = 0;
1570
            int client_id = 0;
1571

    
1572
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1573
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1574
                    logline = p;
1575
                    break;
1576
                }
1577
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1578
                    client_id = strtol(p + 18, 0, 10);
1579
                p = strchr(p, '\n');
1580
                if (!p)
1581
                    break;
1582

    
1583
                p++;
1584
            }
1585

    
1586
            if (logline) {
1587
                char *eol = strchr(logline, '\n');
1588

    
1589
                logline += 17;
1590

    
1591
                if (eol) {
1592
                    if (eol[-1] == '\r')
1593
                        eol--;
1594
                    http_log("%.*s\n", (int) (eol - logline), logline);
1595
                    c->suppress_log = 1;
1596
                }
1597
            }
1598

    
1599
#ifdef DEBUG_WMP
1600
            http_log("\nGot request:\n%s\n", c->buffer);
1601
#endif
1602

    
1603
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1604
                HTTPContext *wmpc;
1605

    
1606
                /* Now we have to find the client_id */
1607
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1608
                    if (wmpc->wmp_client_id == client_id)
1609
                        break;
1610
                }
1611

    
1612
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1613
                    wmpc->switch_pending = 1;
1614
            }
1615

    
1616
            snprintf(msg, sizeof(msg), "POST command not handled");
1617
            c->stream = 0;
1618
            goto send_error;
1619
        }
1620
        if (http_start_receive_data(c) < 0) {
1621
            snprintf(msg, sizeof(msg), "could not open feed");
1622
            goto send_error;
1623
        }
1624
        c->http_error = 0;
1625
        c->state = HTTPSTATE_RECEIVE_DATA;
1626
        return 0;
1627
    }
1628

    
1629
#ifdef DEBUG_WMP
1630
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1631
        http_log("\nGot request:\n%s\n", c->buffer);
1632
#endif
1633

    
1634
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1635
        goto send_status;
1636

    
1637
    /* open input stream */
1638
    if (open_input_stream(c, info) < 0) {
1639
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1640
        goto send_error;
1641
    }
1642

    
1643
    /* prepare http header */
1644
    q = c->buffer;
1645
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1646
    mime_type = c->stream->fmt->mime_type;
1647
    if (!mime_type)
1648
        mime_type = "application/x-octet-stream";
1649
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1650

    
1651
    /* for asf, we need extra headers */
1652
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1653
        /* Need to allocate a client id */
1654

    
1655
        c->wmp_client_id = av_lfg_get(&random_state);
1656

    
1657
        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);
1658
    }
1659
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1660
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1661

    
1662
    /* prepare output buffer */
1663
    c->http_error = 0;
1664
    c->buffer_ptr = c->buffer;
1665
    c->buffer_end = q;
1666
    c->state = HTTPSTATE_SEND_HEADER;
1667
    return 0;
1668
 send_error:
1669
    c->http_error = 404;
1670
    q = c->buffer;
1671
    q += snprintf(q, c->buffer_size,
1672
                  "HTTP/1.0 404 Not Found\r\n"
1673
                  "Content-type: text/html\r\n"
1674
                  "\r\n"
1675
                  "<html>\n"
1676
                  "<head><title>404 Not Found</title></head>\n"
1677
                  "<body>%s</body>\n"
1678
                  "</html>\n", msg);
1679
    /* prepare output buffer */
1680
    c->buffer_ptr = c->buffer;
1681
    c->buffer_end = q;
1682
    c->state = HTTPSTATE_SEND_HEADER;
1683
    return 0;
1684
 send_status:
1685
    compute_status(c);
1686
    c->http_error = 200; /* horrible : we use this value to avoid
1687
                            going to the send data state */
1688
    c->state = HTTPSTATE_SEND_HEADER;
1689
    return 0;
1690
}
1691

    
1692
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1693
{
1694
    static const char *suffix = " kMGTP";
1695
    const char *s;
1696

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

    
1699
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1700
}
1701

    
1702
static void compute_status(HTTPContext *c)
1703
{
1704
    HTTPContext *c1;
1705
    FFStream *stream;
1706
    char *p;
1707
    time_t ti;
1708
    int i, len;
1709
    ByteIOContext *pb;
1710

    
1711
    if (url_open_dyn_buf(&pb) < 0) {
1712
        /* XXX: return an error ? */
1713
        c->buffer_ptr = c->buffer;
1714
        c->buffer_end = c->buffer;
1715
        return;
1716
    }
1717

    
1718
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1719
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1720
    url_fprintf(pb, "Pragma: no-cache\r\n");
1721
    url_fprintf(pb, "\r\n");
1722

    
1723
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1724
    if (c->stream->feed_filename[0])
1725
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1726
    url_fprintf(pb, "</head>\n<body>");
1727
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1728
    /* format status */
1729
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1730
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1731
    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");
1732
    stream = first_stream;
1733
    while (stream != NULL) {
1734
        char sfilename[1024];
1735
        char *eosf;
1736

    
1737
        if (stream->feed != stream) {
1738
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1739
            eosf = sfilename + strlen(sfilename);
1740
            if (eosf - sfilename >= 4) {
1741
                if (strcmp(eosf - 4, ".asf") == 0)
1742
                    strcpy(eosf - 4, ".asx");
1743
                else if (strcmp(eosf - 3, ".rm") == 0)
1744
                    strcpy(eosf - 3, ".ram");
1745
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1746
                    /* generate a sample RTSP director if
1747
                       unicast. Generate an SDP redirector if
1748
                       multicast */
1749
                    eosf = strrchr(sfilename, '.');
1750
                    if (!eosf)
1751
                        eosf = sfilename + strlen(sfilename);
1752
                    if (stream->is_multicast)
1753
                        strcpy(eosf, ".sdp");
1754
                    else
1755
                        strcpy(eosf, ".rtsp");
1756
                }
1757
            }
1758

    
1759
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1760
                         sfilename, stream->filename);
1761
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1762
                        stream->conns_served);
1763
            fmt_bytecount(pb, stream->bytes_served);
1764
            switch(stream->stream_type) {
1765
            case STREAM_TYPE_LIVE: {
1766
                    int audio_bit_rate = 0;
1767
                    int video_bit_rate = 0;
1768
                    const char *audio_codec_name = "";
1769
                    const char *video_codec_name = "";
1770
                    const char *audio_codec_name_extra = "";
1771
                    const char *video_codec_name_extra = "";
1772

    
1773
                    for(i=0;i<stream->nb_streams;i++) {
1774
                        AVStream *st = stream->streams[i];
1775
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1776
                        switch(st->codec->codec_type) {
1777
                        case CODEC_TYPE_AUDIO:
1778
                            audio_bit_rate += st->codec->bit_rate;
1779
                            if (codec) {
1780
                                if (*audio_codec_name)
1781
                                    audio_codec_name_extra = "...";
1782
                                audio_codec_name = codec->name;
1783
                            }
1784
                            break;
1785
                        case CODEC_TYPE_VIDEO:
1786
                            video_bit_rate += st->codec->bit_rate;
1787
                            if (codec) {
1788
                                if (*video_codec_name)
1789
                                    video_codec_name_extra = "...";
1790
                                video_codec_name = codec->name;
1791
                            }
1792
                            break;
1793
                        case CODEC_TYPE_DATA:
1794
                            video_bit_rate += st->codec->bit_rate;
1795
                            break;
1796
                        default:
1797
                            abort();
1798
                        }
1799
                    }
1800
                    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",
1801
                                 stream->fmt->name,
1802
                                 stream->bandwidth,
1803
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1804
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1805
                    if (stream->feed)
1806
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1807
                    else
1808
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1809
                    url_fprintf(pb, "\n");
1810
                }
1811
                break;
1812
            default:
1813
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1814
                break;
1815
            }
1816
        }
1817
        stream = stream->next;
1818
    }
1819
    url_fprintf(pb, "</table>\n");
1820

    
1821
    stream = first_stream;
1822
    while (stream != NULL) {
1823
        if (stream->feed == stream) {
1824
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1825
            if (stream->pid) {
1826
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1827

    
1828
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1829
                {
1830
                    FILE *pid_stat;
1831
                    char ps_cmd[64];
1832

    
1833
                    /* This is somewhat linux specific I guess */
1834
                    snprintf(ps_cmd, sizeof(ps_cmd),
1835
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1836
                             stream->pid);
1837

    
1838
                    pid_stat = popen(ps_cmd, "r");
1839
                    if (pid_stat) {
1840
                        char cpuperc[10];
1841
                        char cpuused[64];
1842

    
1843
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1844
                                   cpuused) == 2) {
1845
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1846
                                         cpuperc, cpuused);
1847
                        }
1848
                        fclose(pid_stat);
1849
                    }
1850
                }
1851
#endif
1852

    
1853
                url_fprintf(pb, "<p>");
1854
            }
1855
            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");
1856

    
1857
            for (i = 0; i < stream->nb_streams; i++) {
1858
                AVStream *st = stream->streams[i];
1859
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1860
                const char *type = "unknown";
1861
                char parameters[64];
1862

    
1863
                parameters[0] = 0;
1864

    
1865
                switch(st->codec->codec_type) {
1866
                case CODEC_TYPE_AUDIO:
1867
                    type = "audio";
1868
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1869
                    break;
1870
                case CODEC_TYPE_VIDEO:
1871
                    type = "video";
1872
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1873
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1874
                    break;
1875
                default:
1876
                    abort();
1877
                }
1878
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1879
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1880
            }
1881
            url_fprintf(pb, "</table>\n");
1882

    
1883
        }
1884
        stream = stream->next;
1885
    }
1886

    
1887
    /* connection status */
1888
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1889

    
1890
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1891
                 nb_connections, nb_max_connections);
1892

    
1893
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1894
                 current_bandwidth, max_bandwidth);
1895

    
1896
    url_fprintf(pb, "<table>\n");
1897
    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");
1898
    c1 = first_http_ctx;
1899
    i = 0;
1900
    while (c1 != NULL) {
1901
        int bitrate;
1902
        int j;
1903

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

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

    
1933
    /* date */
1934
    ti = time(NULL);
1935
    p = ctime(&ti);
1936
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1937
    url_fprintf(pb, "</body>\n</html>\n");
1938

    
1939
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1940
    c->buffer_ptr = c->pb_buffer;
1941
    c->buffer_end = c->pb_buffer + len;
1942
}
1943

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

    
1950
    if (!st->codec->codec) {
1951
        codec = avcodec_find_decoder(st->codec->codec_id);
1952
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1953
            st->codec->parse_only = 1;
1954
            if (avcodec_open(st->codec, codec) < 0)
1955
                st->codec->parse_only = 0;
1956
        }
1957
    }
1958
}
1959

    
1960
static int open_input_stream(HTTPContext *c, const char *info)
1961
{
1962
    char buf[128];
1963
    char input_filename[1024];
1964
    AVFormatContext *s;
1965
    int buf_size, i, ret;
1966
    int64_t stream_pos;
1967

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

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

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

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

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

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

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

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

    
2057

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

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

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

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

    
2093
        c->got_key_frame = 0;
2094

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

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

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

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

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

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

    
2219
                    if (c->is_packetized) {
2220
                        int max_packet_size;
2221
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2222
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2223
                        else
2224
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2225
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2226
                    } else {
2227
                        ret = url_open_dyn_buf(&ctx->pb);
2228
                    }
2229
                    if (ret < 0) {
2230
                        /* XXX: potential leak */
2231
                        return -1;
2232
                    }
2233
                    ost = ctx->streams[pkt.stream_index];
2234

    
2235
                    ctx->pb->is_streamed = 1;
2236
                    if (pkt.dts != AV_NOPTS_VALUE)
2237
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2238
                    if (pkt.pts != AV_NOPTS_VALUE)
2239
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2240
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2241
                    if (av_write_frame(ctx, &pkt) < 0) {
2242
                        http_log("Error writing frame to output\n");
2243
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2244
                    }
2245

    
2246
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2247
                    c->cur_frame_bytes = len;
2248
                    c->buffer_ptr = c->pb_buffer;
2249
                    c->buffer_end = c->pb_buffer + len;
2250

    
2251
                    codec->frame_number++;
2252
                    if (len == 0) {
2253
                        av_free_packet(&pkt);
2254
                        goto redo;
2255
                    }
2256
                }
2257
                av_free_packet(&pkt);
2258
            }
2259
        }
2260
        break;
2261
    default:
2262
    case HTTPSTATE_SEND_DATA_TRAILER:
2263
        /* last packet test ? */
2264
        if (c->last_packet_sent || c->is_packetized)
2265
            return -1;
2266
        ctx = &c->fmt_ctx;
2267
        /* prepare header */
2268
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2269
            /* XXX: potential leak */
2270
            return -1;
2271
        }
2272
        c->fmt_ctx.pb->is_streamed = 1;
2273
        av_write_trailer(ctx);
2274
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2275
        c->buffer_ptr = c->pb_buffer;
2276
        c->buffer_end = c->pb_buffer + len;
2277

    
2278
        c->last_packet_sent = 1;
2279
        break;
2280
    }
2281
    return 0;
2282
}
2283

    
2284
/* should convert the format at the same time */
2285
/* send data starting at c->buffer_ptr to the output connection
2286
   (either UDP or TCP connection) */
2287
static int http_send_data(HTTPContext *c)
2288
{
2289
    int len, ret;
2290

    
2291
    for(;;) {
2292
        if (c->buffer_ptr >= c->buffer_end) {
2293
            ret = http_prepare_data(c);
2294
            if (ret < 0)
2295
                return -1;
2296
            else if (ret != 0)
2297
                /* state change requested */
2298
                break;
2299
        } else {
2300
            if (c->is_packetized) {
2301
                /* RTP data output */
2302
                len = c->buffer_end - c->buffer_ptr;
2303
                if (len < 4) {
2304
                    /* fail safe - should never happen */
2305
                fail1:
2306
                    c->buffer_ptr = c->buffer_end;
2307
                    return 0;
2308
                }
2309
                len = (c->buffer_ptr[0] << 24) |
2310
                    (c->buffer_ptr[1] << 16) |
2311
                    (c->buffer_ptr[2] << 8) |
2312
                    (c->buffer_ptr[3]);
2313
                if (len > (c->buffer_end - c->buffer_ptr))
2314
                    goto fail1;
2315
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2316
                    /* nothing to send yet: we can wait */
2317
                    return 0;
2318
                }
2319

    
2320
                c->data_count += len;
2321
                update_datarate(&c->datarate, c->data_count);
2322
                if (c->stream)
2323
                    c->stream->bytes_served += len;
2324

    
2325
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2326
                    /* RTP packets are sent inside the RTSP TCP connection */
2327
                    ByteIOContext *pb;
2328
                    int interleaved_index, size;
2329
                    uint8_t header[4];
2330
                    HTTPContext *rtsp_c;
2331

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

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

    
2395
                c->data_count += len;
2396
                update_datarate(&c->datarate, c->data_count);
2397
                if (c->stream)
2398
                    c->stream->bytes_served += len;
2399
                break;
2400
            }
2401
        }
2402
    } /* for(;;) */
2403
    return 0;
2404
}
2405

    
2406
static int http_start_receive_data(HTTPContext *c)
2407
{
2408
    int fd;
2409

    
2410
    if (c->stream->feed_opened)
2411
        return -1;
2412

    
2413
    /* Don't permit writing to this one */
2414
    if (c->stream->readonly)
2415
        return -1;
2416

    
2417
    /* open feed */
2418
    fd = open(c->stream->feed_filename, O_RDWR);
2419
    if (fd < 0) {
2420
        http_log("Error opening feeder file: %s\n", strerror(errno));
2421
        return -1;
2422
    }
2423
    c->feed_fd = fd;
2424

    
2425
    if (c->stream->truncate) {
2426
        /* truncate feed file */
2427
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2428
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2429
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2430
    } else {
2431
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2432
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2433
            return -1;
2434
        }
2435
    }
2436

    
2437
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2438
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2439
    lseek(fd, 0, SEEK_SET);
2440

    
2441
    /* init buffer input */
2442
    c->buffer_ptr = c->buffer;
2443
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2444
    c->stream->feed_opened = 1;
2445
    c->chunked_encoding = !!strcasestr(c->buffer, "Transfer-Encoding: chunked");
2446
    return 0;
2447
}
2448

    
2449
static int http_receive_data(HTTPContext *c)
2450
{
2451
    HTTPContext *c1;
2452
    int len, loop_run = 0;
2453

    
2454
    while (c->chunked_encoding && !c->chunk_size &&
2455
           c->buffer_end > c->buffer_ptr) {
2456
        /* read chunk header, if present */
2457
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2458

    
2459
        if (len < 0) {
2460
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2461
                ff_neterrno() != FF_NETERROR(EINTR))
2462
                /* error : close connection */
2463
                goto fail;
2464
        } else if (len == 0) {
2465
            /* end of connection : close it */
2466
            goto fail;
2467
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2468
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2469
            c->chunk_size = strtol(c->buffer, 0, 16);
2470
            if (c->chunk_size == 0) // end of stream
2471
                goto fail;
2472
            c->buffer_ptr = c->buffer;
2473
            break;
2474
        } else if (++loop_run > 10) {
2475
            /* no chunk header, abort */
2476
            goto fail;
2477
        } else {
2478
            c->buffer_ptr++;
2479
        }
2480
    }
2481

    
2482
    if (c->buffer_end > c->buffer_ptr) {
2483
        len = recv(c->fd, c->buffer_ptr,
2484
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2485
        if (len < 0) {
2486
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2487
                ff_neterrno() != FF_NETERROR(EINTR))
2488
                /* error : close connection */
2489
                goto fail;
2490
        } else if (len == 0)
2491
            /* end of connection : close it */
2492
            goto fail;
2493
        else {
2494
            c->chunk_size -= len;
2495
            c->buffer_ptr += len;
2496
            c->data_count += len;
2497
            update_datarate(&c->datarate, c->data_count);
2498
        }
2499
    }
2500

    
2501
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2502
        if (c->buffer[0] != 'f' ||
2503
            c->buffer[1] != 'm') {
2504
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2505
            goto fail;
2506
        }
2507
    }
2508

    
2509
    if (c->buffer_ptr >= c->buffer_end) {
2510
        FFStream *feed = c->stream;
2511
        /* a packet has been received : write it in the store, except
2512
           if header */
2513
        if (c->data_count > FFM_PACKET_SIZE) {
2514

    
2515
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2516
            /* XXX: use llseek or url_seek */
2517
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2518
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2519
                http_log("Error writing to feed file: %s\n", strerror(errno));
2520
                goto fail;
2521
            }
2522

    
2523
            feed->feed_write_index += FFM_PACKET_SIZE;
2524
            /* update file size */
2525
            if (feed->feed_write_index > c->stream->feed_size)
2526
                feed->feed_size = feed->feed_write_index;
2527

    
2528
            /* handle wrap around if max file size reached */
2529
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2530
                feed->feed_write_index = FFM_PACKET_SIZE;
2531

    
2532
            /* write index */
2533
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2534
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2535
                goto fail;
2536
            }
2537

    
2538
            /* wake up any waiting connections */
2539
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2540
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2541
                    c1->stream->feed == c->stream->feed)
2542
                    c1->state = HTTPSTATE_SEND_DATA;
2543
            }
2544
        } else {
2545
            /* We have a header in our hands that contains useful data */
2546
            AVFormatContext *s = NULL;
2547
            ByteIOContext *pb;
2548
            AVInputFormat *fmt_in;
2549
            int i;
2550

    
2551
            /* use feed output format name to find corresponding input format */
2552
            fmt_in = av_find_input_format(feed->fmt->name);
2553
            if (!fmt_in)
2554
                goto fail;
2555

    
2556
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2557
            pb->is_streamed = 1;
2558

    
2559
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2560
                av_free(pb);
2561
                goto fail;
2562
            }
2563

    
2564
            /* Now we have the actual streams */
2565
            if (s->nb_streams != feed->nb_streams) {
2566
                av_close_input_stream(s);
2567
                av_free(pb);
2568
                http_log("Feed '%s' stream number does not match registered feed\n",
2569
                         c->stream->feed_filename);
2570
                goto fail;
2571
            }
2572

    
2573
            for (i = 0; i < s->nb_streams; i++) {
2574
                AVStream *fst = feed->streams[i];
2575
                AVStream *st = s->streams[i];
2576
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2577
                if (fst->codec->extradata_size) {
2578
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2579
                    if (!fst->codec->extradata)
2580
                        goto fail;
2581
                    memcpy(fst->codec->extradata, st->codec->extradata,
2582
                           fst->codec->extradata_size);
2583
                }
2584
            }
2585

    
2586
            av_close_input_stream(s);
2587
            av_free(pb);
2588
        }
2589
        c->buffer_ptr = c->buffer;
2590
    }
2591

    
2592
    return 0;
2593
 fail:
2594
    c->stream->feed_opened = 0;
2595
    close(c->feed_fd);
2596
    /* wake up any waiting connections to stop waiting for feed */
2597
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2598
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2599
            c1->stream->feed == c->stream->feed)
2600
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2601
    }
2602
    return -1;
2603
}
2604

    
2605
/********************************************************************/
2606
/* RTSP handling */
2607

    
2608
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2609
{
2610
    const char *str;
2611
    time_t ti;
2612
    char *p;
2613
    char buf2[32];
2614

    
2615
    switch(error_number) {
2616
    case RTSP_STATUS_OK:
2617
        str = "OK";
2618
        break;
2619
    case RTSP_STATUS_METHOD:
2620
        str = "Method Not Allowed";
2621
        break;
2622
    case RTSP_STATUS_BANDWIDTH:
2623
        str = "Not Enough Bandwidth";
2624
        break;
2625
    case RTSP_STATUS_SESSION:
2626
        str = "Session Not Found";
2627
        break;
2628
    case RTSP_STATUS_STATE:
2629
        str = "Method Not Valid in This State";
2630
        break;
2631
    case RTSP_STATUS_AGGREGATE:
2632
        str = "Aggregate operation not allowed";
2633
        break;
2634
    case RTSP_STATUS_ONLY_AGGREGATE:
2635
        str = "Only aggregate operation allowed";
2636
        break;
2637
    case RTSP_STATUS_TRANSPORT:
2638
        str = "Unsupported transport";
2639
        break;
2640
    case RTSP_STATUS_INTERNAL:
2641
        str = "Internal Server Error";
2642
        break;
2643
    case RTSP_STATUS_SERVICE:
2644
        str = "Service Unavailable";
2645
        break;
2646
    case RTSP_STATUS_VERSION:
2647
        str = "RTSP Version not supported";
2648
        break;
2649
    default:
2650
        str = "Unknown Error";
2651
        break;
2652
    }
2653

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

    
2657
    /* output GMT time */
2658
    ti = time(NULL);
2659
    p = ctime(&ti);
2660
    strcpy(buf2, p);
2661
    p = buf2 + strlen(p) - 1;
2662
    if (*p == '\n')
2663
        *p = '\0';
2664
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2665
}
2666

    
2667
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2668
{
2669
    rtsp_reply_header(c, error_number);
2670
    url_fprintf(c->pb, "\r\n");
2671
}
2672

    
2673
static int rtsp_parse_request(HTTPContext *c)
2674
{
2675
    const char *p, *p1, *p2;
2676
    char cmd[32];
2677
    char url[1024];
2678
    char protocol[32];
2679
    char line[1024];
2680
    int len;
2681
    RTSPMessageHeader header1, *header = &header1;
2682

    
2683
    c->buffer_ptr[0] = '\0';
2684
    p = c->buffer;
2685

    
2686
    get_word(cmd, sizeof(cmd), &p);
2687
    get_word(url, sizeof(url), &p);
2688
    get_word(protocol, sizeof(protocol), &p);
2689

    
2690
    av_strlcpy(c->method, cmd, sizeof(c->method));
2691
    av_strlcpy(c->url, url, sizeof(c->url));
2692
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2693

    
2694
    if (url_open_dyn_buf(&c->pb) < 0) {
2695
        /* XXX: cannot do more */
2696
        c->pb = NULL; /* safety */
2697
        return -1;
2698
    }
2699

    
2700
    /* check version name */
2701
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2702
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2703
        goto the_end;
2704
    }
2705

    
2706
    /* parse each header line */
2707
    memset(header, 0, sizeof(*header));
2708
    /* skip to next line */
2709
    while (*p != '\n' && *p != '\0')
2710
        p++;
2711
    if (*p == '\n')
2712
        p++;
2713
    while (*p != '\0') {
2714
        p1 = strchr(p, '\n');
2715
        if (!p1)
2716
            break;
2717
        p2 = p1;
2718
        if (p2 > p && p2[-1] == '\r')
2719
            p2--;
2720
        /* skip empty line */
2721
        if (p2 == p)
2722
            break;
2723
        len = p2 - p;
2724
        if (len > sizeof(line) - 1)
2725
            len = sizeof(line) - 1;
2726
        memcpy(line, p, len);
2727
        line[len] = '\0';
2728
        ff_rtsp_parse_line(header, line);
2729
        p = p1 + 1;
2730
    }
2731

    
2732
    /* handle sequence number */
2733
    c->seq = header->seq;
2734

    
2735
    if (!strcmp(cmd, "DESCRIBE"))
2736
        rtsp_cmd_describe(c, url);
2737
    else if (!strcmp(cmd, "OPTIONS"))
2738
        rtsp_cmd_options(c, url);
2739
    else if (!strcmp(cmd, "SETUP"))
2740
        rtsp_cmd_setup(c, url, header);
2741
    else if (!strcmp(cmd, "PLAY"))
2742
        rtsp_cmd_play(c, url, header);
2743
    else if (!strcmp(cmd, "PAUSE"))
2744
        rtsp_cmd_pause(c, url, header);
2745
    else if (!strcmp(cmd, "TEARDOWN"))
2746
        rtsp_cmd_teardown(c, url, header);
2747
    else
2748
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2749

    
2750
 the_end:
2751
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2752
    c->pb = NULL; /* safety */
2753
    if (len < 0) {
2754
        /* XXX: cannot do more */
2755
        return -1;
2756
    }
2757
    c->buffer_ptr = c->pb_buffer;
2758
    c->buffer_end = c->pb_buffer + len;
2759
    c->state = RTSPSTATE_SEND_REPLY;
2760
    return 0;
2761
}
2762

    
2763
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2764
                                   struct in_addr my_ip)
2765
{
2766
    AVFormatContext *avc;
2767
    AVStream avs[MAX_STREAMS];
2768
    int i;
2769

    
2770
    avc =  avformat_alloc_context();
2771
    if (avc == NULL) {
2772
        return -1;
2773
    }
2774
    av_metadata_set(&avc->metadata, "title",
2775
                    stream->title[0] ? stream->title : "No Title");
2776
    avc->nb_streams = stream->nb_streams;
2777
    if (stream->is_multicast) {
2778
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2779
                 inet_ntoa(stream->multicast_ip),
2780
                 stream->multicast_port, stream->multicast_ttl);
2781
    }
2782

    
2783
    for(i = 0; i < stream->nb_streams; i++) {
2784
        avc->streams[i] = &avs[i];
2785
        avc->streams[i]->codec = stream->streams[i]->codec;
2786
    }
2787
    *pbuffer = av_mallocz(2048);
2788
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2789
    av_free(avc);
2790

    
2791
    return strlen(*pbuffer);
2792
}
2793

    
2794
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2795
{
2796
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2797
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2798
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2799
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2800
    url_fprintf(c->pb, "\r\n");
2801
}
2802

    
2803
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2804
{
2805
    FFStream *stream;
2806
    char path1[1024];
2807
    const char *path;
2808
    uint8_t *content;
2809
    int content_length, len;
2810
    struct sockaddr_in my_addr;
2811

    
2812
    /* find which url is asked */
2813
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2814
    path = path1;
2815
    if (*path == '/')
2816
        path++;
2817

    
2818
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2819
        if (!stream->is_feed &&
2820
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2821
            !strcmp(path, stream->filename)) {
2822
            goto found;
2823
        }
2824
    }
2825
    /* no stream found */
2826
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2827
    return;
2828

    
2829
 found:
2830
    /* prepare the media description in sdp format */
2831

    
2832
    /* get the host IP */
2833
    len = sizeof(my_addr);
2834
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2835
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2836
    if (content_length < 0) {
2837
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2838
        return;
2839
    }
2840
    rtsp_reply_header(c, RTSP_STATUS_OK);
2841
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2842
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2843
    url_fprintf(c->pb, "\r\n");
2844
    put_buffer(c->pb, content, content_length);
2845
}
2846

    
2847
static HTTPContext *find_rtp_session(const char *session_id)
2848
{
2849
    HTTPContext *c;
2850

    
2851
    if (session_id[0] == '\0')
2852
        return NULL;
2853

    
2854
    for(c = first_http_ctx; c != NULL; c = c->next) {
2855
        if (!strcmp(c->session_id, session_id))
2856
            return c;
2857
    }
2858
    return NULL;
2859
}
2860

    
2861
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2862
{
2863
    RTSPTransportField *th;
2864
    int i;
2865

    
2866
    for(i=0;i<h->nb_transports;i++) {
2867
        th = &h->transports[i];
2868
        if (th->lower_transport == lower_transport)
2869
            return th;
2870
    }
2871
    return NULL;
2872
}
2873

    
2874
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2875
                           RTSPMessageHeader *h)
2876
{
2877
    FFStream *stream;
2878
    int stream_index, port;
2879
    char buf[1024];
2880
    char path1[1024];
2881
    const char *path;
2882
    HTTPContext *rtp_c;
2883
    RTSPTransportField *th;
2884
    struct sockaddr_in dest_addr;
2885
    RTSPActionServerSetup setup;
2886

    
2887
    /* find which url is asked */
2888
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2889
    path = path1;
2890
    if (*path == '/')
2891
        path++;
2892

    
2893
    /* now check each stream */
2894
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2895
        if (!stream->is_feed &&
2896
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2897
            /* accept aggregate filenames only if single stream */
2898
            if (!strcmp(path, stream->filename)) {
2899
                if (stream->nb_streams != 1) {
2900
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2901
                    return;
2902
                }
2903
                stream_index = 0;
2904
                goto found;
2905
            }
2906

    
2907
            for(stream_index = 0; stream_index < stream->nb_streams;
2908
                stream_index++) {
2909
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2910
                         stream->filename, stream_index);
2911
                if (!strcmp(path, buf))
2912
                    goto found;
2913
            }
2914
        }
2915
    }
2916
    /* no stream found */
2917
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2918
    return;
2919
 found:
2920

    
2921
    /* generate session id if needed */
2922
    if (h->session_id[0] == '\0')
2923
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2924
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2925

    
2926
    /* find rtp session, and create it if none found */
2927
    rtp_c = find_rtp_session(h->session_id);
2928
    if (!rtp_c) {
2929
        /* always prefer UDP */
2930
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2931
        if (!th) {
2932
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2933
            if (!th) {
2934
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2935
                return;
2936
            }
2937
        }
2938

    
2939
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2940
                                   th->lower_transport);
2941
        if (!rtp_c) {
2942
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2943
            return;
2944
        }
2945

    
2946
        /* open input stream */
2947
        if (open_input_stream(rtp_c, "") < 0) {
2948
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2949
            return;
2950
        }
2951
    }
2952

    
2953
    /* test if stream is OK (test needed because several SETUP needs
2954
       to be done for a given file) */
2955
    if (rtp_c->stream != stream) {
2956
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2957
        return;
2958
    }
2959

    
2960
    /* test if stream is already set up */
2961
    if (rtp_c->rtp_ctx[stream_index]) {
2962
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2963
        return;
2964
    }
2965

    
2966
    /* check transport */
2967
    th = find_transport(h, rtp_c->rtp_protocol);
2968
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2969
                th->client_port_min <= 0)) {
2970
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2971
        return;
2972
    }
2973

    
2974
    /* setup default options */
2975
    setup.transport_option[0] = '\0';
2976
    dest_addr = rtp_c->from_addr;
2977
    dest_addr.sin_port = htons(th->client_port_min);
2978

    
2979
    /* setup stream */
2980
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2981
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2982
        return;
2983
    }
2984

    
2985
    /* now everything is OK, so we can send the connection parameters */
2986
    rtsp_reply_header(c, RTSP_STATUS_OK);
2987
    /* session ID */
2988
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2989

    
2990
    switch(rtp_c->rtp_protocol) {
2991
    case RTSP_LOWER_TRANSPORT_UDP:
2992
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2993
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2994
                    "client_port=%d-%d;server_port=%d-%d",
2995
                    th->client_port_min, th->client_port_min + 1,
2996
                    port, port + 1);
2997
        break;
2998
    case RTSP_LOWER_TRANSPORT_TCP:
2999
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3000
                    stream_index * 2, stream_index * 2 + 1);
3001
        break;
3002
    default:
3003
        break;
3004
    }
3005
    if (setup.transport_option[0] != '\0')
3006
        url_fprintf(c->pb, ";%s", setup.transport_option);
3007
    url_fprintf(c->pb, "\r\n");
3008

    
3009

    
3010
    url_fprintf(c->pb, "\r\n");
3011
}
3012

    
3013

    
3014
/* find an rtp connection by using the session ID. Check consistency
3015
   with filename */
3016
static HTTPContext *find_rtp_session_with_url(const char *url,
3017
                                              const char *session_id)
3018
{
3019
    HTTPContext *rtp_c;
3020
    char path1[1024];
3021
    const char *path;
3022
    char buf[1024];
3023
    int s;
3024

    
3025
    rtp_c = find_rtp_session(session_id);
3026
    if (!rtp_c)
3027
        return NULL;
3028

    
3029
    /* find which url is asked */
3030
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3031
    path = path1;
3032
    if (*path == '/')
3033
        path++;
3034
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3035
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3036
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3037
        rtp_c->stream->filename, s);
3038
      if(!strncmp(path, buf, sizeof(buf))) {
3039
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3040
        return rtp_c;
3041
      }
3042
    }
3043
    return NULL;
3044
}
3045

    
3046
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3047
{
3048
    HTTPContext *rtp_c;
3049

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

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

    
3063
    rtp_c->state = HTTPSTATE_SEND_DATA;
3064

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

    
3072
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3073
{
3074
    HTTPContext *rtp_c;
3075

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

    
3082
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3083
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3084
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3085
        return;
3086
    }
3087

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

    
3097
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3098
{
3099
    HTTPContext *rtp_c;
3100
    char session_id[32];
3101

    
3102
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3103
    if (!rtp_c) {
3104
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3105
        return;
3106
    }
3107

    
3108
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3109

    
3110
    /* abort the session */
3111
    close_connection(rtp_c);
3112

    
3113
    /* now everything is OK, so we can send the connection parameters */
3114
    rtsp_reply_header(c, RTSP_STATUS_OK);
3115
    /* session ID */
3116
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3117
    url_fprintf(c->pb, "\r\n");
3118
}
3119

    
3120

    
3121
/********************************************************************/
3122
/* RTP handling */
3123

    
3124
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3125
                                       FFStream *stream, const char *session_id,
3126
                                       enum RTSPLowerTransport rtp_protocol)
3127
{
3128
    HTTPContext *c = NULL;
3129
    const char *proto_str;
3130

    
3131
    /* XXX: should output a warning page when coming
3132
       close to the connection limit */
3133
    if (nb_connections >= nb_max_connections)
3134
        goto fail;
3135

    
3136
    /* add a new connection */
3137
    c = av_mallocz(sizeof(HTTPContext));
3138
    if (!c)
3139
        goto fail;
3140

    
3141
    c->fd = -1;
3142
    c->poll_entry = NULL;
3143
    c->from_addr = *from_addr;
3144
    c->buffer_size = IOBUFFER_INIT_SIZE;
3145
    c->buffer = av_malloc(c->buffer_size);
3146
    if (!c->buffer)
3147
        goto fail;
3148
    nb_connections++;
3149
    c->stream = stream;
3150
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3151
    c->state = HTTPSTATE_READY;
3152
    c->is_packetized = 1;
3153
    c->rtp_protocol = rtp_protocol;
3154

    
3155
    /* protocol is shown in statistics */
3156
    switch(c->rtp_protocol) {
3157
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3158
        proto_str = "MCAST";
3159
        break;
3160
    case RTSP_LOWER_TRANSPORT_UDP:
3161
        proto_str = "UDP";
3162
        break;
3163
    case RTSP_LOWER_TRANSPORT_TCP:
3164
        proto_str = "TCP";
3165
        break;
3166
    default:
3167
        proto_str = "???";
3168
        break;
3169
    }
3170
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3171
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3172

    
3173
    current_bandwidth += stream->bandwidth;
3174

    
3175
    c->next = first_http_ctx;
3176
    first_http_ctx = c;
3177
    return c;
3178

    
3179
 fail:
3180
    if (c) {
3181
        av_free(c->buffer);
3182
        av_free(c);
3183
    }
3184
    return NULL;
3185
}
3186

    
3187
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3188
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3189
   used. */
3190
static int rtp_new_av_stream(HTTPContext *c,
3191
                             int stream_index, struct sockaddr_in *dest_addr,
3192
                             HTTPContext *rtsp_c)
3193
{
3194
    AVFormatContext *ctx;
3195
    AVStream *st;
3196
    char *ipaddr;
3197
    URLContext *h = NULL;
3198
    uint8_t *dummy_buf;
3199
    int max_packet_size;
3200

    
3201
    /* now we can open the relevant output stream */
3202
    ctx = avformat_alloc_context();
3203
    if (!ctx)
3204
        return -1;
3205
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3206

    
3207
    st = av_mallocz(sizeof(AVStream));
3208
    if (!st)
3209
        goto fail;
3210
    st->codec= avcodec_alloc_context();
3211
    ctx->nb_streams = 1;
3212
    ctx->streams[0] = st;
3213

    
3214
    if (!c->stream->feed ||
3215
        c->stream->feed == c->stream)
3216
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3217
    else
3218
        memcpy(st,
3219
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3220
               sizeof(AVStream));
3221
    st->priv_data = NULL;
3222

    
3223
    /* build destination RTP address */
3224
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3225

    
3226
    switch(c->rtp_protocol) {
3227
    case RTSP_LOWER_TRANSPORT_UDP:
3228
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3229
        /* RTP/UDP case */
3230

    
3231
        /* XXX: also pass as parameter to function ? */
3232
        if (c->stream->is_multicast) {
3233
            int ttl;
3234
            ttl = c->stream->multicast_ttl;
3235
            if (!ttl)
3236
                ttl = 16;
3237
            snprintf(ctx->filename, sizeof(ctx->filename),
3238
                     "rtp://%s:%d?multicast=1&ttl=%d",
3239
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3240
        } else {
3241
            snprintf(ctx->filename, sizeof(ctx->filename),
3242
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3243
        }
3244

    
3245
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3246
            goto fail;
3247
        c->rtp_handles[stream_index] = h;
3248
        max_packet_size = url_get_max_packet_size(h);
3249
        break;
3250
    case RTSP_LOWER_TRANSPORT_TCP:
3251
        /* RTP/TCP case */
3252
        c->rtsp_c = rtsp_c;
3253
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3254
        break;
3255
    default:
3256
        goto fail;
3257
    }
3258

    
3259
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3260
             ipaddr, ntohs(dest_addr->sin_port),
3261
             c->stream->filename, stream_index, c->protocol);
3262

    
3263
    /* normally, no packets should be output here, but the packet size may be checked */
3264
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3265
        /* XXX: close stream */
3266
        goto fail;
3267
    }
3268
    av_set_parameters(ctx, NULL);
3269
    if (av_write_header(ctx) < 0) {
3270
    fail:
3271
        if (h)
3272
            url_close(h);
3273
        av_free(ctx);
3274
        return -1;
3275
    }
3276
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3277
    av_free(dummy_buf);
3278

    
3279
    c->rtp_ctx[stream_index] = ctx;
3280
    return 0;
3281
}
3282

    
3283
/********************************************************************/
3284
/* ffserver initialization */
3285

    
3286
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3287
{
3288
    AVStream *fst;
3289

    
3290
    fst = av_mallocz(sizeof(AVStream));
3291
    if (!fst)
3292
        return NULL;
3293
    fst->codec= avcodec_alloc_context();
3294
    fst->priv_data = av_mallocz(sizeof(FeedData));
3295
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3296
    fst->index = stream->nb_streams;
3297
    av_set_pts_info(fst, 33, 1, 90000);
3298
    stream->streams[stream->nb_streams++] = fst;
3299
    return fst;
3300
}
3301

    
3302
/* return the stream number in the feed */
3303
static int add_av_stream(FFStream *feed, AVStream *st)
3304
{
3305
    AVStream *fst;
3306
    AVCodecContext *av, *av1;
3307
    int i;
3308

    
3309
    av = st->codec;
3310
    for(i=0;i<feed->nb_streams;i++) {
3311
        st = feed->streams[i];
3312
        av1 = st->codec;
3313
        if (av1->codec_id == av->codec_id &&
3314
            av1->codec_type == av->codec_type &&
3315
            av1->bit_rate == av->bit_rate) {
3316

    
3317
            switch(av->codec_type) {
3318
            case CODEC_TYPE_AUDIO:
3319
                if (av1->channels == av->channels &&
3320
                    av1->sample_rate == av->sample_rate)
3321
                    goto found;
3322
                break;
3323
            case CODEC_TYPE_VIDEO:
3324
                if (av1->width == av->width &&
3325
                    av1->height == av->height &&
3326
                    av1->time_base.den == av->time_base.den &&
3327
                    av1->time_base.num == av->time_base.num &&
3328
                    av1->gop_size == av->gop_size)
3329
                    goto found;
3330
                break;
3331
            default:
3332
                abort();
3333
            }
3334
        }
3335
    }
3336

    
3337
    fst = add_av_stream1(feed, av);
3338
    if (!fst)
3339
        return -1;
3340
    return feed->nb_streams - 1;
3341
 found:
3342
    return i;
3343
}
3344

    
3345
static void remove_stream(FFStream *stream)
3346
{
3347
    FFStream **ps;
3348
    ps = &first_stream;
3349
    while (*ps != NULL) {
3350
        if (*ps == stream)
3351
            *ps = (*ps)->next;
3352
        else
3353
            ps = &(*ps)->next;
3354
    }
3355
}
3356

    
3357
/* specific mpeg4 handling : we extract the raw parameters */
3358
static void extract_mpeg4_header(AVFormatContext *infile)
3359
{
3360
    int mpeg4_count, i, size;
3361
    AVPacket pkt;
3362
    AVStream *st;
3363
    const uint8_t *p;
3364

    
3365
    mpeg4_count = 0;
3366
    for(i=0;i<infile->nb_streams;i++) {
3367
        st = infile->streams[i];
3368
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3369
            st->codec->extradata_size == 0) {
3370
            mpeg4_count++;
3371
        }
3372
    }
3373
    if (!mpeg4_count)
3374
        return;
3375

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

    
3406
/* compute the needed AVStream for each file */
3407
static void build_file_streams(void)
3408
{
3409
    FFStream *stream, *stream_next;
3410
    AVFormatContext *infile;
3411
    int i, ret;
3412

    
3413
    /* gather all streams */
3414
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3415
        stream_next = stream->next;
3416
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3417
            !stream->feed) {
3418
            /* the stream comes from a file */
3419
            /* try to open the file */
3420
            /* open stream */
3421
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3422
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3423
                /* specific case : if transport stream output to RTP,
3424
                   we use a raw transport stream reader */
3425
                stream->ap_in->mpeg2ts_raw = 1;
3426
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3427
            }
3428

    
3429
            http_log("Opening file '%s'\n", stream->feed_filename);
3430
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3431
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3432
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3433
                /* remove stream (no need to spend more time on it) */
3434
            fail:
3435
                remove_stream(stream);
3436
            } else {
3437
                /* find all the AVStreams inside and reference them in
3438
                   'stream' */
3439
                if (av_find_stream_info(infile) < 0) {
3440
                    http_log("Could not find codec parameters from '%s'\n",
3441
                             stream->feed_filename);
3442
                    av_close_input_file(infile);
3443
                    goto fail;
3444
                }
3445
                extract_mpeg4_header(infile);
3446

    
3447
                for(i=0;i<infile->nb_streams;i++)
3448
                    add_av_stream1(stream, infile->streams[i]->codec);
3449

    
3450
                av_close_input_file(infile);
3451
            }
3452
        }
3453
    }
3454
}
3455

    
3456
/* compute the needed AVStream for each feed */
3457
static void build_feed_streams(void)
3458
{
3459
    FFStream *stream, *feed;
3460
    int i;
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
                /* we handle a stream coming from a feed */
3468
                for(i=0;i<stream->nb_streams;i++)
3469
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3470
            }
3471
        }
3472
    }
3473

    
3474
    /* gather all streams */
3475
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3476
        feed = stream->feed;
3477
        if (feed) {
3478
            if (stream->is_feed) {
3479
                for(i=0;i<stream->nb_streams;i++)
3480
                    stream->feed_streams[i] = i;
3481
            }
3482
        }
3483
    }
3484

    
3485
    /* create feed files if needed */
3486
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3487
        int fd;
3488

    
3489
        if (url_exist(feed->feed_filename)) {
3490
            /* See if it matches */
3491
            AVFormatContext *s;
3492
            int matches = 0;
3493

    
3494
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3495
                /* Now see if it matches */
3496
                if (s->nb_streams == feed->nb_streams) {
3497
                    matches = 1;
3498
                    for(i=0;i<s->nb_streams;i++) {
3499
                        AVStream *sf, *ss;
3500
                        sf = feed->streams[i];
3501
                        ss = s->streams[i];
3502

    
3503
                        if (sf->index != ss->index ||
3504
                            sf->id != ss->id) {
3505
                            http_log("Index & Id do not match for stream %d (%s)\n",
3506
                                   i, feed->feed_filename);
3507
                            matches = 0;
3508
                        } else {
3509
                            AVCodecContext *ccf, *ccs;
3510

    
3511
                            ccf = sf->codec;
3512
                            ccs = ss->codec;
3513
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3514

    
3515
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3516
                                http_log("Codecs do not match for stream %d\n", i);
3517
                                matches = 0;
3518
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3519
                                http_log("Codec bitrates do not match for stream %d\n", i);
3520
                                matches = 0;
3521
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3522
                                if (CHECK_CODEC(time_base.den) ||
3523
                                    CHECK_CODEC(time_base.num) ||
3524
                                    CHECK_CODEC(width) ||
3525
                                    CHECK_CODEC(height)) {
3526
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3527
                                    matches = 0;
3528
                                }
3529
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3530
                                if (CHECK_CODEC(sample_rate) ||
3531
                                    CHECK_CODEC(channels) ||
3532
                                    CHECK_CODEC(frame_size)) {
3533
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3534
                                    matches = 0;
3535
                                }
3536
                            } else {
3537
                                http_log("Unknown codec type\n");
3538
                                matches = 0;
3539
                            }
3540
                        }
3541
                        if (!matches)
3542
                            break;
3543
                    }
3544
                } else
3545
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3546
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3547

    
3548
                av_close_input_file(s);
3549
            } else
3550
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3551
                        feed->feed_filename);
3552

    
3553
            if (!matches) {
3554
                if (feed->readonly) {
3555
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3556
                        feed->feed_filename);
3557
                    exit(1);
3558
                }
3559
                unlink(feed->feed_filename);
3560
            }
3561
        }
3562
        if (!url_exist(feed->feed_filename)) {
3563
            AVFormatContext s1 = {0}, *s = &s1;
3564

    
3565
            if (feed->readonly) {
3566
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3567
                    feed->feed_filename);
3568
                exit(1);
3569
            }
3570

    
3571
            /* only write the header of the ffm file */
3572
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3573
                http_log("Could not open output feed file '%s'\n",
3574
                         feed->feed_filename);
3575
                exit(1);
3576
            }
3577
            s->oformat = feed->fmt;
3578
            s->nb_streams = feed->nb_streams;
3579
            for(i=0;i<s->nb_streams;i++) {
3580
                AVStream *st;
3581
                st = feed->streams[i];
3582
                s->streams[i] = st;
3583
            }
3584
            av_set_parameters(s, NULL);
3585
            if (av_write_header(s) < 0) {
3586
                http_log("Container doesn't supports the required parameters\n");
3587
                exit(1);
3588
            }
3589
            /* XXX: need better api */
3590
            av_freep(&s->priv_data);
3591
            url_fclose(s->pb);
3592
        }
3593
        /* get feed size and write index */
3594
        fd = open(feed->feed_filename, O_RDONLY);
3595
        if (fd < 0) {
3596
            http_log("Could not open output feed file '%s'\n",
3597
                    feed->feed_filename);
3598
            exit(1);
3599
        }
3600

    
3601
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3602
        feed->feed_size = lseek(fd, 0, SEEK_END);
3603
        /* ensure that we do not wrap before the end of file */
3604
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3605
            feed->feed_max_size = feed->feed_size;
3606

    
3607
        close(fd);
3608
    }
3609
}
3610

    
3611
/* compute the bandwidth used by each stream */
3612
static void compute_bandwidth(void)
3613
{
3614
    unsigned bandwidth;
3615
    int i;
3616
    FFStream *stream;
3617

    
3618
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3619
        bandwidth = 0;
3620
        for(i=0;i<stream->nb_streams;i++) {
3621
            AVStream *st = stream->streams[i];
3622
            switch(st->codec->codec_type) {
3623
            case CODEC_TYPE_AUDIO:
3624
            case CODEC_TYPE_VIDEO:
3625
                bandwidth += st->codec->bit_rate;
3626
                break;
3627
            default:
3628
                break;
3629
            }
3630
        }
3631
        stream->bandwidth = (bandwidth + 999) / 1000;
3632
    }
3633
}
3634

    
3635
/* add a codec and set the default parameters */
3636
static void add_codec(FFStream *stream, AVCodecContext *av)
3637
{
3638
    AVStream *st;
3639

    
3640
    /* compute default parameters */
3641
    switch(av->codec_type) {
3642
    case CODEC_TYPE_AUDIO:
3643
        if (av->bit_rate == 0)
3644
            av->bit_rate = 64000;
3645
        if (av->sample_rate == 0)
3646
            av->sample_rate = 22050;
3647
        if (av->channels == 0)
3648
            av->channels = 1;
3649
        break;
3650
    case CODEC_TYPE_VIDEO:
3651
        if (av->bit_rate == 0)
3652
            av->bit_rate = 64000;
3653
        if (av->time_base.num == 0){
3654
            av->time_base.den = 5;
3655
            av->time_base.num = 1;
3656
        }
3657
        if (av->width == 0 || av->height == 0) {
3658
            av->width = 160;
3659
            av->height = 128;
3660
        }
3661
        /* Bitrate tolerance is less for streaming */
3662
        if (av->bit_rate_tolerance == 0)
3663
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3664
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3665
        if (av->qmin == 0)
3666
            av->qmin = 3;
3667
        if (av->qmax == 0)
3668
            av->qmax = 31;
3669
        if (av->max_qdiff == 0)
3670
            av->max_qdiff = 3;
3671
        av->qcompress = 0.5;
3672
        av->qblur = 0.5;
3673

    
3674
        if (!av->nsse_weight)
3675
            av->nsse_weight = 8;
3676

    
3677
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3678
        av->me_method = ME_EPZS;
3679
        av->rc_buffer_aggressivity = 1.0;
3680

    
3681
        if (!av->rc_eq)
3682
            av->rc_eq = "tex^qComp";
3683
        if (!av->i_quant_factor)
3684
            av->i_quant_factor = -0.8;
3685
        if (!av->b_quant_factor)
3686
            av->b_quant_factor = 1.25;
3687
        if (!av->b_quant_offset)
3688
            av->b_quant_offset = 1.25;
3689
        if (!av->rc_max_rate)
3690
            av->rc_max_rate = av->bit_rate * 2;
3691

    
3692
        if (av->rc_max_rate && !av->rc_buffer_size) {
3693
            av->rc_buffer_size = av->rc_max_rate;
3694
        }
3695

    
3696

    
3697
        break;
3698
    default:
3699
        abort();
3700
    }
3701

    
3702
    st = av_mallocz(sizeof(AVStream));
3703
    if (!st)
3704
        return;
3705
    st->codec = avcodec_alloc_context();
3706
    stream->streams[stream->nb_streams++] = st;
3707
    memcpy(st->codec, av, sizeof(AVCodecContext));
3708
}
3709

    
3710
static enum CodecID opt_audio_codec(const char *arg)
3711
{
3712
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3713

    
3714
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3715
        return CODEC_ID_NONE;
3716

    
3717
    return p->id;
3718
}
3719

    
3720
static enum CodecID opt_video_codec(const char *arg)
3721
{
3722
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3723

    
3724
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3725
        return CODEC_ID_NONE;
3726

    
3727
    return p->id;
3728
}
3729

    
3730
/* simplistic plugin support */
3731

    
3732
#if HAVE_DLOPEN
3733
static void load_module(const char *filename)
3734
{
3735
    void *dll;
3736
    void (*init_func)(void);
3737
    dll = dlopen(filename, RTLD_NOW);
3738
    if (!dll) {
3739
        fprintf(stderr, "Could not load module '%s' - %s\n",
3740
                filename, dlerror());
3741
        return;
3742
    }
3743

    
3744
    init_func = dlsym(dll, "ffserver_module_init");
3745
    if (!init_func) {
3746
        fprintf(stderr,
3747
                "%s: init function 'ffserver_module_init()' not found\n",
3748
                filename);
3749
        dlclose(dll);
3750
    }
3751

    
3752
    init_func();
3753
}
3754
#endif
3755

    
3756
static int ffserver_opt_default(const char *opt, const char *arg,
3757
                       AVCodecContext *avctx, int type)
3758
{
3759
    int ret = 0;
3760
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3761
    if(o)
3762
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3763
    return ret;
3764
}
3765

    
3766
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3767
                                             const char *mime_type)
3768
{
3769
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3770

    
3771
    if (fmt) {
3772
        AVOutputFormat *stream_fmt;
3773
        char stream_format_name[64];
3774

    
3775
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3776
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3777

    
3778
        if (stream_fmt)
3779
            fmt = stream_fmt;
3780
    }
3781

    
3782
    return fmt;
3783
}
3784

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4507
    need_to_start_children = 1;
4508
}
4509

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

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

    
4525
static const OptionDef options[] = {
4526
#include "cmdutils_common_opts.h"
4527
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4528
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4529
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4530
    { NULL },
4531
};
4532

    
4533
int main(int argc, char **argv)
4534
{
4535
    struct sigaction sigact;
4536

    
4537
    av_register_all();
4538

    
4539
    show_banner();
4540

    
4541
    config_filename = "/etc/ffserver.conf";
4542

    
4543
    my_program_name = argv[0];
4544
    my_program_dir = getcwd(0, 0);
4545
    ffserver_daemon = 1;
4546

    
4547
    parse_options(argc, argv, options, NULL);
4548

    
4549
    unsetenv("http_proxy");             /* Kill the http_proxy */
4550

    
4551
    av_lfg_init(&random_state, ff_random_get_seed());
4552

    
4553
    memset(&sigact, 0, sizeof(sigact));
4554
    sigact.sa_handler = handle_child_exit;
4555
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4556
    sigaction(SIGCHLD, &sigact, 0);
4557

    
4558
    if (parse_ffconfig(config_filename) < 0) {
4559
        fprintf(stderr, "Incorrect config file - exiting.\n");
4560
        exit(1);
4561
    }
4562

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

    
4572
    build_file_streams();
4573

    
4574
    build_feed_streams();
4575

    
4576
    compute_bandwidth();
4577

    
4578
    /* put the process in background and detach it from its TTY */
4579
    if (ffserver_daemon) {
4580
        int pid;
4581

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

    
4603
    /* signal init */
4604
    signal(SIGPIPE, SIG_IGN);
4605

    
4606
    if (ffserver_daemon)
4607
        chdir("/");
4608

    
4609
    if (http_server() < 0) {
4610
        http_log("Could not start server\n");
4611
        exit(1);
4612
    }
4613

    
4614
    return 0;
4615
}