Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 6580d5e3

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 "libavcodec/opt.h"
41
#include <stdarg.h>
42
#include <unistd.h>
43
#include <fcntl.h>
44
#include <sys/ioctl.h>
45
#if HAVE_POLL_H
46
#include <poll.h>
47
#endif
48
#include <errno.h>
49
#include <sys/time.h>
50
#include <time.h>
51
#include <sys/wait.h>
52
#include <signal.h>
53
#if HAVE_DLFCN_H
54
#include <dlfcn.h>
55
#endif
56

    
57
#include "cmdutils.h"
58

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

    
62
static const OptionDef options[];
63

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

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

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

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

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

    
95
#define IOBUFFER_INIT_SIZE 8192
96

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

    
101
#define SYNC_TIMEOUT (10 * 1000)
102

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
312
static AVLFG random_state;
313

    
314
static FILE *logfile = NULL;
315

    
316
static char *ctime1(char *buf2)
317
{
318
    time_t ti;
319
    char *p;
320

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

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

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

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

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

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

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

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

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

    
397

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

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

    
407
            feed->pid = fork();
408

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

    
419
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
420

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

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

    
434
                for (i = 3; i < 256; i++)
435
                    close(i);
436

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

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

    
450
                signal(SIGPIPE, SIG_DFL);
451

    
452
                execvp(pathname, feed->child_argv);
453

    
454
                _exit(1);
455
            }
456
        }
457
    }
458
}
459

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

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

    
471
    tmp = 1;
472
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
473

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

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

    
489
    return server_fd;
490
}
491

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

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

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

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

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

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

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

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

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

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

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

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

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

    
577
    http_log("FFserver started.\n");
578

    
579
    start_children(first_feed);
580

    
581
    start_multicast();
582

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

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

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

    
655
        cur_time = av_gettime() / 1000;
656

    
657
        if (need_to_start_children) {
658
            need_to_start_children = 0;
659
            start_children(first_feed);
660
        }
661

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

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

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

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

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

    
717

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

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

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

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

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

    
751
    c->next = first_http_ctx;
752
    first_http_ctx = c;
753
    nb_connections++;
754

    
755
    start_wait_request(c, is_rtsp);
756

    
757
    return;
758

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

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

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

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

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

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

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

    
820
    ctx = &c->fmt_ctx;
821

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

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

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

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

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

    
852
static int handle_connection(HTTPContext *c)
853
{
854
    int len, ret;
855

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

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

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

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

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

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

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

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

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

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

    
1037
            while (*q && *q != '\n' && isspace(*q))
1038
                q++;
1039

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

    
1044
                q += 20;
1045

    
1046
                memset(rates, 0xff, ratelen);
1047

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

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

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

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

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

    
1070
        p++;
1071
    }
1072

    
1073
    return 0;
1074
}
1075

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

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

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

    
1091
        /* Potential stream */
1092

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

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

    
1110
    return best;
1111
}
1112

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

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

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

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

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

    
1148
    return action_required;
1149
}
1150

    
1151

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

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

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

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

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

    
1193
static void get_arg(char *buf, int buf_size, const char **pp)
1194
{
1195
    const char *p;
1196
    char *q;
1197
    int quote;
1198

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

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

    
1232
    for (acl = stream->acl; acl; acl = acl->next) {
1233
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1234
            return (acl->action == IP_ALLOW) ? 1 : 0;
1235
        last_action = acl->action;
1236
    }
1237

    
1238
    /* Nothing matched, so return not the last action */
1239
    return (last_action == IP_DENY) ? 1 : 0;
1240
}
1241

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

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

    
1268
enum RedirType {
1269
    REDIR_NONE,
1270
    REDIR_ASX,
1271
    REDIR_RAM,
1272
    REDIR_ASF,
1273
    REDIR_RTSP,
1274
    REDIR_SDP,
1275
};
1276

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

    
1293
    p = c->buffer;
1294
    get_word(cmd, sizeof(cmd), (const char **)&p);
1295
    av_strlcpy(c->method, cmd, sizeof(c->method));
1296

    
1297
    if (!strcmp(cmd, "GET"))
1298
        c->post = 0;
1299
    else if (!strcmp(cmd, "POST"))
1300
        c->post = 1;
1301
    else
1302
        return -1;
1303

    
1304
    get_word(url, sizeof(url), (const char **)&p);
1305
    av_strlcpy(c->url, url, sizeof(c->url));
1306

    
1307
    get_word(protocol, sizeof(protocol), (const char **)&p);
1308
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1309
        return -1;
1310

    
1311
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1312

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

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

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

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

    
1337
        p++;
1338
    }
1339

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

    
1359
    // "redirect" / request to index.html
1360
    if (!strlen(filename))
1361
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1362

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

    
1375
    c->stream = stream;
1376
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1377
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1378

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

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

    
1407
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1408
        current_bandwidth += stream->bandwidth;
1409

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

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

    
1436
    if (redir_type != REDIR_NONE) {
1437
        char *hostinfo = 0;
1438

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

    
1448
            p++;
1449
        }
1450

    
1451
        if (hostinfo) {
1452
            char *eoh;
1453
            char hostbuf[260];
1454

    
1455
            while (isspace(*hostinfo))
1456
                hostinfo++;
1457

    
1458
            eoh = strchr(hostinfo, '\n');
1459
            if (eoh) {
1460
                if (eoh[-1] == '\r')
1461
                    eoh--;
1462

    
1463
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1464
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1465
                    hostbuf[eoh - hostinfo] = 0;
1466

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

    
1518
                            q += snprintf(q, c->buffer_size,
1519
                                          "HTTP/1.0 200 OK\r\n"
1520
                                          "Content-type: application/sdp\r\n"
1521
                                          "\r\n");
1522

    
1523
                            len = sizeof(my_addr);
1524
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1525

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

    
1543
                    /* prepare output buffer */
1544
                    c->buffer_ptr = c->buffer;
1545
                    c->buffer_end = q;
1546
                    c->state = HTTPSTATE_SEND_HEADER;
1547
                    return 0;
1548
                }
1549
            }
1550
        }
1551

    
1552
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1553
        goto send_error;
1554
    }
1555

    
1556
    stream->conns_served++;
1557

    
1558
    /* XXX: add there authenticate and IP match */
1559

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

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

    
1579
                p++;
1580
            }
1581

    
1582
            if (logline) {
1583
                char *eol = strchr(logline, '\n');
1584

    
1585
                logline += 17;
1586

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

    
1595
#ifdef DEBUG_WMP
1596
            http_log("\nGot request:\n%s\n", c->buffer);
1597
#endif
1598

    
1599
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1600
                HTTPContext *wmpc;
1601

    
1602
                /* Now we have to find the client_id */
1603
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1604
                    if (wmpc->wmp_client_id == client_id)
1605
                        break;
1606
                }
1607

    
1608
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1609
                    wmpc->switch_pending = 1;
1610
            }
1611

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

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

    
1630
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1631
        goto send_status;
1632

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

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

    
1647
    /* for asf, we need extra headers */
1648
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1649
        /* Need to allocate a client id */
1650

    
1651
        c->wmp_client_id = av_lfg_get(&random_state);
1652

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

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

    
1688
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1689
{
1690
    static const char *suffix = " kMGTP";
1691
    const char *s;
1692

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

    
1695
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1696
}
1697

    
1698
static void compute_status(HTTPContext *c)
1699
{
1700
    HTTPContext *c1;
1701
    FFStream *stream;
1702
    char *p;
1703
    time_t ti;
1704
    int i, len;
1705
    ByteIOContext *pb;
1706

    
1707
    if (url_open_dyn_buf(&pb) < 0) {
1708
        /* XXX: return an error ? */
1709
        c->buffer_ptr = c->buffer;
1710
        c->buffer_end = c->buffer;
1711
        return;
1712
    }
1713

    
1714
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1715
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1716
    url_fprintf(pb, "Pragma: no-cache\r\n");
1717
    url_fprintf(pb, "\r\n");
1718

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

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

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

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

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

    
1824
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1825
                {
1826
                    FILE *pid_stat;
1827
                    char ps_cmd[64];
1828

    
1829
                    /* This is somewhat linux specific I guess */
1830
                    snprintf(ps_cmd, sizeof(ps_cmd),
1831
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1832
                             stream->pid);
1833

    
1834
                    pid_stat = popen(ps_cmd, "r");
1835
                    if (pid_stat) {
1836
                        char cpuperc[10];
1837
                        char cpuused[64];
1838

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

    
1849
                url_fprintf(pb, "<p>");
1850
            }
1851
            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");
1852

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

    
1859
                parameters[0] = 0;
1860

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

    
1879
        }
1880
        stream = stream->next;
1881
    }
1882

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

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

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

    
1892
    url_fprintf(pb, "<table>\n");
1893
    url_fprintf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1894
    c1 = first_http_ctx;
1895
    i = 0;
1896
    while (c1 != NULL) {
1897
        int bitrate;
1898
        int j;
1899

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

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

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

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

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

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

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

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

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

    
2006
    /* open each parser */
2007
    for(i=0;i<s->nb_streams;i++)
2008
        open_parser(s, i);
2009

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

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

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

    
2037
/* return the estimated time at which the current packet must be sent
2038
   (in us) */
2039
static int64_t get_packet_send_clock(HTTPContext *c)
2040
{
2041
    int bytes_left, bytes_sent, frame_bytes;
2042

    
2043
    frame_bytes = c->cur_frame_bytes;
2044
    if (frame_bytes <= 0)
2045
        return c->cur_pts;
2046
    else {
2047
        bytes_left = c->buffer_end - c->buffer_ptr;
2048
        bytes_sent = frame_bytes - bytes_left;
2049
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2050
    }
2051
}
2052

    
2053

    
2054
static int http_prepare_data(HTTPContext *c)
2055
{
2056
    int i, len, ret;
2057
    AVFormatContext *ctx;
2058

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

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

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

    
2089
        c->got_key_frame = 0;
2090

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

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

    
2106
        av_set_parameters(&c->fmt_ctx, NULL);
2107
        if (av_write_header(&c->fmt_ctx) < 0) {
2108
            http_log("Error writing output header\n");
2109
            return -1;
2110
        }
2111

    
2112
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2113
        c->buffer_ptr = c->pb_buffer;
2114
        c->buffer_end = c->pb_buffer + len;
2115

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

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

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

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

    
2242
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2243
                    c->cur_frame_bytes = len;
2244
                    c->buffer_ptr = c->pb_buffer;
2245
                    c->buffer_end = c->pb_buffer + len;
2246

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

    
2274
        c->last_packet_sent = 1;
2275
        break;
2276
    }
2277
    return 0;
2278
}
2279

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

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

    
2316
                c->data_count += len;
2317
                update_datarate(&c->datarate, c->data_count);
2318
                if (c->stream)
2319
                    c->stream->bytes_served += len;
2320

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

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

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

    
2391
                c->data_count += len;
2392
                update_datarate(&c->datarate, c->data_count);
2393
                if (c->stream)
2394
                    c->stream->bytes_served += len;
2395
                break;
2396
            }
2397
        }
2398
    } /* for(;;) */
2399
    return 0;
2400
}
2401

    
2402
static int http_start_receive_data(HTTPContext *c)
2403
{
2404
    int fd;
2405

    
2406
    if (c->stream->feed_opened)
2407
        return -1;
2408

    
2409
    /* Don't permit writing to this one */
2410
    if (c->stream->readonly)
2411
        return -1;
2412

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

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

    
2433
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2434
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2435
    lseek(fd, 0, SEEK_SET);
2436

    
2437
    /* init buffer input */
2438
    c->buffer_ptr = c->buffer;
2439
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2440
    c->stream->feed_opened = 1;
2441
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2442
    return 0;
2443
}
2444

    
2445
static int http_receive_data(HTTPContext *c)
2446
{
2447
    HTTPContext *c1;
2448
    int len, loop_run = 0;
2449

    
2450
    while (c->chunked_encoding && !c->chunk_size &&
2451
           c->buffer_end > c->buffer_ptr) {
2452
        /* read chunk header, if present */
2453
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2454

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

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

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

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

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

    
2519
            feed->feed_write_index += FFM_PACKET_SIZE;
2520
            /* update file size */
2521
            if (feed->feed_write_index > c->stream->feed_size)
2522
                feed->feed_size = feed->feed_write_index;
2523

    
2524
            /* handle wrap around if max file size reached */
2525
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2526
                feed->feed_write_index = FFM_PACKET_SIZE;
2527

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

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

    
2547
            /* use feed output format name to find corresponding input format */
2548
            fmt_in = av_find_input_format(feed->fmt->name);
2549
            if (!fmt_in)
2550
                goto fail;
2551

    
2552
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2553
            pb->is_streamed = 1;
2554

    
2555
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2556
                av_free(pb);
2557
                goto fail;
2558
            }
2559

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

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

    
2582
            av_close_input_stream(s);
2583
            av_free(pb);
2584
        }
2585
        c->buffer_ptr = c->buffer;
2586
    }
2587

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

    
2601
/********************************************************************/
2602
/* RTSP handling */
2603

    
2604
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2605
{
2606
    const char *str;
2607
    time_t ti;
2608
    char *p;
2609
    char buf2[32];
2610

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

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

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

    
2663
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2664
{
2665
    rtsp_reply_header(c, error_number);
2666
    url_fprintf(c->pb, "\r\n");
2667
}
2668

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

    
2679
    c->buffer_ptr[0] = '\0';
2680
    p = c->buffer;
2681

    
2682
    get_word(cmd, sizeof(cmd), &p);
2683
    get_word(url, sizeof(url), &p);
2684
    get_word(protocol, sizeof(protocol), &p);
2685

    
2686
    av_strlcpy(c->method, cmd, sizeof(c->method));
2687
    av_strlcpy(c->url, url, sizeof(c->url));
2688
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2689

    
2690
    if (url_open_dyn_buf(&c->pb) < 0) {
2691
        /* XXX: cannot do more */
2692
        c->pb = NULL; /* safety */
2693
        return -1;
2694
    }
2695

    
2696
    /* check version name */
2697
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2698
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2699
        goto the_end;
2700
    }
2701

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

    
2728
    /* handle sequence number */
2729
    c->seq = header->seq;
2730

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

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

    
2759
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2760
                                   struct in_addr my_ip)
2761
{
2762
    AVFormatContext *avc;
2763
    AVStream avs[MAX_STREAMS];
2764
    int i;
2765

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

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

    
2787
    return strlen(*pbuffer);
2788
}
2789

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

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

    
2808
    /* find which url is asked */
2809
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2810
    path = path1;
2811
    if (*path == '/')
2812
        path++;
2813

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

    
2825
 found:
2826
    /* prepare the media description in sdp format */
2827

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

    
2843
static HTTPContext *find_rtp_session(const char *session_id)
2844
{
2845
    HTTPContext *c;
2846

    
2847
    if (session_id[0] == '\0')
2848
        return NULL;
2849

    
2850
    for(c = first_http_ctx; c != NULL; c = c->next) {
2851
        if (!strcmp(c->session_id, session_id))
2852
            return c;
2853
    }
2854
    return NULL;
2855
}
2856

    
2857
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2858
{
2859
    RTSPTransportField *th;
2860
    int i;
2861

    
2862
    for(i=0;i<h->nb_transports;i++) {
2863
        th = &h->transports[i];
2864
        if (th->lower_transport == lower_transport)
2865
            return th;
2866
    }
2867
    return NULL;
2868
}
2869

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

    
2883
    /* find which url is asked */
2884
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2885
    path = path1;
2886
    if (*path == '/')
2887
        path++;
2888

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

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

    
2917
    /* generate session id if needed */
2918
    if (h->session_id[0] == '\0')
2919
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2920
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2921

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

    
2935
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2936
                                   th->lower_transport);
2937
        if (!rtp_c) {
2938
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2939
            return;
2940
        }
2941

    
2942
        /* open input stream */
2943
        if (open_input_stream(rtp_c, "") < 0) {
2944
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2945
            return;
2946
        }
2947
    }
2948

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

    
2956
    /* test if stream is already set up */
2957
    if (rtp_c->rtp_ctx[stream_index]) {
2958
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2959
        return;
2960
    }
2961

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

    
2970
    /* setup default options */
2971
    setup.transport_option[0] = '\0';
2972
    dest_addr = rtp_c->from_addr;
2973
    dest_addr.sin_port = htons(th->client_port_min);
2974

    
2975
    /* setup stream */
2976
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2977
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2978
        return;
2979
    }
2980

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

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

    
3005

    
3006
    url_fprintf(c->pb, "\r\n");
3007
}
3008

    
3009

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

    
3021
    rtp_c = find_rtp_session(session_id);
3022
    if (!rtp_c)
3023
        return NULL;
3024

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

    
3042
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3043
{
3044
    HTTPContext *rtp_c;
3045

    
3046
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3047
    if (!rtp_c) {
3048
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3049
        return;
3050
    }
3051

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

    
3059
    rtp_c->state = HTTPSTATE_SEND_DATA;
3060

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

    
3068
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3069
{
3070
    HTTPContext *rtp_c;
3071

    
3072
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3073
    if (!rtp_c) {
3074
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3075
        return;
3076
    }
3077

    
3078
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3079
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3080
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3081
        return;
3082
    }
3083

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

    
3093
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3094
{
3095
    HTTPContext *rtp_c;
3096
    char session_id[32];
3097

    
3098
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3099
    if (!rtp_c) {
3100
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3101
        return;
3102
    }
3103

    
3104
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3105

    
3106
    /* abort the session */
3107
    close_connection(rtp_c);
3108

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

    
3116

    
3117
/********************************************************************/
3118
/* RTP handling */
3119

    
3120
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3121
                                       FFStream *stream, const char *session_id,
3122
                                       enum RTSPLowerTransport rtp_protocol)
3123
{
3124
    HTTPContext *c = NULL;
3125
    const char *proto_str;
3126

    
3127
    /* XXX: should output a warning page when coming
3128
       close to the connection limit */
3129
    if (nb_connections >= nb_max_connections)
3130
        goto fail;
3131

    
3132
    /* add a new connection */
3133
    c = av_mallocz(sizeof(HTTPContext));
3134
    if (!c)
3135
        goto fail;
3136

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

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

    
3169
    current_bandwidth += stream->bandwidth;
3170

    
3171
    c->next = first_http_ctx;
3172
    first_http_ctx = c;
3173
    return c;
3174

    
3175
 fail:
3176
    if (c) {
3177
        av_free(c->buffer);
3178
        av_free(c);
3179
    }
3180
    return NULL;
3181
}
3182

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

    
3197
    /* now we can open the relevant output stream */
3198
    ctx = avformat_alloc_context();
3199
    if (!ctx)
3200
        return -1;
3201
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3202

    
3203
    st = av_mallocz(sizeof(AVStream));
3204
    if (!st)
3205
        goto fail;
3206
    st->codec= avcodec_alloc_context();
3207
    ctx->nb_streams = 1;
3208
    ctx->streams[0] = st;
3209

    
3210
    if (!c->stream->feed ||
3211
        c->stream->feed == c->stream)
3212
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3213
    else
3214
        memcpy(st,
3215
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3216
               sizeof(AVStream));
3217
    st->priv_data = NULL;
3218

    
3219
    /* build destination RTP address */
3220
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3221

    
3222
    switch(c->rtp_protocol) {
3223
    case RTSP_LOWER_TRANSPORT_UDP:
3224
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3225
        /* RTP/UDP case */
3226

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

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

    
3255
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3256
             ipaddr, ntohs(dest_addr->sin_port),
3257
             c->stream->filename, stream_index, c->protocol);
3258

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

    
3275
    c->rtp_ctx[stream_index] = ctx;
3276
    return 0;
3277
}
3278

    
3279
/********************************************************************/
3280
/* ffserver initialization */
3281

    
3282
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3283
{
3284
    AVStream *fst;
3285

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

    
3298
/* return the stream number in the feed */
3299
static int add_av_stream(FFStream *feed, AVStream *st)
3300
{
3301
    AVStream *fst;
3302
    AVCodecContext *av, *av1;
3303
    int i;
3304

    
3305
    av = st->codec;
3306
    for(i=0;i<feed->nb_streams;i++) {
3307
        st = feed->streams[i];
3308
        av1 = st->codec;
3309
        if (av1->codec_id == av->codec_id &&
3310
            av1->codec_type == av->codec_type &&
3311
            av1->bit_rate == av->bit_rate) {
3312

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

    
3333
    fst = add_av_stream1(feed, av);
3334
    if (!fst)
3335
        return -1;
3336
    return feed->nb_streams - 1;
3337
 found:
3338
    return i;
3339
}
3340

    
3341
static void remove_stream(FFStream *stream)
3342
{
3343
    FFStream **ps;
3344
    ps = &first_stream;
3345
    while (*ps != NULL) {
3346
        if (*ps == stream)
3347
            *ps = (*ps)->next;
3348
        else
3349
            ps = &(*ps)->next;
3350
    }
3351
}
3352

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

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

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

    
3402
/* compute the needed AVStream for each file */
3403
static void build_file_streams(void)
3404
{
3405
    FFStream *stream, *stream_next;
3406
    AVFormatContext *infile;
3407
    int i, ret;
3408

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

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

    
3443
                for(i=0;i<infile->nb_streams;i++)
3444
                    add_av_stream1(stream, infile->streams[i]->codec);
3445

    
3446
                av_close_input_file(infile);
3447
            }
3448
        }
3449
    }
3450
}
3451

    
3452
/* compute the needed AVStream for each feed */
3453
static void build_feed_streams(void)
3454
{
3455
    FFStream *stream, *feed;
3456
    int i;
3457

    
3458
    /* gather all streams */
3459
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3460
        feed = stream->feed;
3461
        if (feed) {
3462
            if (!stream->is_feed) {
3463
                /* we handle a stream coming from a feed */
3464
                for(i=0;i<stream->nb_streams;i++)
3465
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3466
            }
3467
        }
3468
    }
3469

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

    
3481
    /* create feed files if needed */
3482
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3483
        int fd;
3484

    
3485
        if (url_exist(feed->feed_filename)) {
3486
            /* See if it matches */
3487
            AVFormatContext *s;
3488
            int matches = 0;
3489

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

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

    
3507
                            ccf = sf->codec;
3508
                            ccs = ss->codec;
3509
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3510

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

    
3544
                av_close_input_file(s);
3545
            } else
3546
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3547
                        feed->feed_filename);
3548

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

    
3561
            if (feed->readonly) {
3562
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3563
                    feed->feed_filename);
3564
                exit(1);
3565
            }
3566

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

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

    
3603
        close(fd);
3604
    }
3605
}
3606

    
3607
/* compute the bandwidth used by each stream */
3608
static void compute_bandwidth(void)
3609
{
3610
    unsigned bandwidth;
3611
    int i;
3612
    FFStream *stream;
3613

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

    
3631
/* add a codec and set the default parameters */
3632
static void add_codec(FFStream *stream, AVCodecContext *av)
3633
{
3634
    AVStream *st;
3635

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

    
3670
        if (!av->nsse_weight)
3671
            av->nsse_weight = 8;
3672

    
3673
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3674
        av->me_method = ME_EPZS;
3675
        av->rc_buffer_aggressivity = 1.0;
3676

    
3677
        if (!av->rc_eq)
3678
            av->rc_eq = "tex^qComp";
3679
        if (!av->i_quant_factor)
3680
            av->i_quant_factor = -0.8;
3681
        if (!av->b_quant_factor)
3682
            av->b_quant_factor = 1.25;
3683
        if (!av->b_quant_offset)
3684
            av->b_quant_offset = 1.25;
3685
        if (!av->rc_max_rate)
3686
            av->rc_max_rate = av->bit_rate * 2;
3687

    
3688
        if (av->rc_max_rate && !av->rc_buffer_size) {
3689
            av->rc_buffer_size = av->rc_max_rate;
3690
        }
3691

    
3692

    
3693
        break;
3694
    default:
3695
        abort();
3696
    }
3697

    
3698
    st = av_mallocz(sizeof(AVStream));
3699
    if (!st)
3700
        return;
3701
    st->codec = avcodec_alloc_context();
3702
    stream->streams[stream->nb_streams++] = st;
3703
    memcpy(st->codec, av, sizeof(AVCodecContext));
3704
}
3705

    
3706
static enum CodecID opt_audio_codec(const char *arg)
3707
{
3708
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3709

    
3710
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3711
        return CODEC_ID_NONE;
3712

    
3713
    return p->id;
3714
}
3715

    
3716
static enum CodecID opt_video_codec(const char *arg)
3717
{
3718
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3719

    
3720
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3721
        return CODEC_ID_NONE;
3722

    
3723
    return p->id;
3724
}
3725

    
3726
/* simplistic plugin support */
3727

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

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

    
3748
    init_func();
3749
}
3750
#endif
3751

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

    
3762
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3763
                                             const char *mime_type)
3764
{
3765
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3766

    
3767
    if (fmt) {
3768
        AVOutputFormat *stream_fmt;
3769
        char stream_format_name[64];
3770

    
3771
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3772
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3773

    
3774
        if (stream_fmt)
3775
            fmt = stream_fmt;
3776
    }
3777

    
3778
    return fmt;
3779
}
3780

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

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

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

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

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

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

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

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

    
3930
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3931

    
3932
                for (i = 0; i < 62; i++) {
3933
                    get_arg(arg, sizeof(arg), &p);
3934
                    if (!arg[0])
3935
                        break;
3936

    
3937
                    feed->child_argv[i] = av_strdup(arg);
3938
                }
3939

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

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

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

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

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

    
4039
                *last_stream = stream;
4040
                last_stream = &stream->next;
4041
            }
4042
        } else if (!strcasecmp(cmd, "Feed")) {
4043
            get_arg(arg, sizeof(arg), &p);
4044
            if (stream) {
4045
                FFStream *sfeed;
4046

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

    
4159
                get_arg(arg, sizeof(arg), &p);
4160

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

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

    
4334
            get_arg(arg, sizeof(arg), &p);
4335

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

    
4343
            get_arg(arg, sizeof(arg), &p);
4344

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

    
4353
            if (!errors) {
4354
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4355
                IPAddressACL **naclp = 0;
4356

    
4357
                acl.next = 0;
4358
                *nacl = acl;
4359

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

    
4370
                if (naclp) {
4371
                    while (*naclp)
4372
                        naclp = &(*naclp)->next;
4373

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

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

    
4474
    fclose(f);
4475
    if (errors)
4476
        return -1;
4477
    else
4478
        return 0;
4479
}
4480

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

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

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

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

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

    
4503
    need_to_start_children = 1;
4504
}
4505

    
4506
static void opt_debug(void)
4507
{
4508
    ffserver_debug = 1;
4509
    ffserver_daemon = 0;
4510
    logfilename[0] = '-';
4511
}
4512

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

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

    
4529
int main(int argc, char **argv)
4530
{
4531
    struct sigaction sigact;
4532

    
4533
    av_register_all();
4534

    
4535
    show_banner();
4536

    
4537
    config_filename = "/etc/ffserver.conf";
4538

    
4539
    my_program_name = argv[0];
4540
    my_program_dir = getcwd(0, 0);
4541
    ffserver_daemon = 1;
4542

    
4543
    parse_options(argc, argv, options, NULL);
4544

    
4545
    unsetenv("http_proxy");             /* Kill the http_proxy */
4546

    
4547
    av_lfg_init(&random_state, ff_random_get_seed());
4548

    
4549
    memset(&sigact, 0, sizeof(sigact));
4550
    sigact.sa_handler = handle_child_exit;
4551
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4552
    sigaction(SIGCHLD, &sigact, 0);
4553

    
4554
    if (parse_ffconfig(config_filename) < 0) {
4555
        fprintf(stderr, "Incorrect config file - exiting.\n");
4556
        exit(1);
4557
    }
4558

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

    
4568
    build_file_streams();
4569

    
4570
    build_feed_streams();
4571

    
4572
    compute_bandwidth();
4573

    
4574
    /* put the process in background and detach it from its TTY */
4575
    if (ffserver_daemon) {
4576
        int pid;
4577

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

    
4599
    /* signal init */
4600
    signal(SIGPIPE, SIG_IGN);
4601

    
4602
    if (ffserver_daemon)
4603
        chdir("/");
4604

    
4605
    if (http_server() < 0) {
4606
        http_log("Could not start server\n");
4607
        exit(1);
4608
    }
4609

    
4610
    return 0;
4611
}