Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ e6f0deab

History | View | Annotate | Download (150 KB)

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

    
22
#include "config.h"
23
#ifndef HAVE_CLOSESOCKET
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "libavutil/random.h"
29
#include "libavutil/avstring.h"
30
#include "libavformat/avformat.h"
31
#include "libavformat/network.h"
32
#include "libavformat/os_support.h"
33
#include "libavformat/rtp.h"
34
#include "libavformat/rtsp.h"
35
#include "libavcodec/opt.h"
36
#include <stdarg.h>
37
#include <unistd.h>
38
#include <fcntl.h>
39
#include <sys/ioctl.h>
40
#ifdef HAVE_POLL_H
41
#include <poll.h>
42
#endif
43
#include <errno.h>
44
#include <sys/time.h>
45
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
46
#include <time.h>
47
#include <sys/wait.h>
48
#include <signal.h>
49
#ifdef HAVE_DLFCN_H
50
#include <dlfcn.h>
51
#endif
52

    
53
#include "cmdutils.h"
54

    
55
#undef exit
56

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

    
60
static const OptionDef options[];
61

    
62
/* maximum number of simultaneous HTTP connections */
63
#define HTTP_MAX_CONNECTIONS 2000
64

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

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

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

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

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

    
96
#define IOBUFFER_INIT_SIZE 8192
97

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

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

    
104
typedef struct {
105
    int64_t count1, count2;
106
    int64_t time1, time2;
107
} DataRateData;
108

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

    
154
    /* RTSP state specific */
155
    uint8_t *pb_buffer; /* XXX: use that in all the code */
156
    ByteIOContext *pb;
157
    int seq; /* RTSP sequence number */
158

    
159
    /* RTP state specific */
160
    enum RTSPProtocol rtp_protocol;
161
    char session_id[32]; /* session id */
162
    AVFormatContext *rtp_ctx[MAX_STREAMS];
163

    
164
    /* RTP/UDP specific */
165
    URLContext *rtp_handles[MAX_STREAMS];
166

    
167
    /* RTP/TCP specific */
168
    struct HTTPContext *rtsp_c;
169
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170
} HTTPContext;
171

    
172
/* each generated stream is described here */
173
enum StreamType {
174
    STREAM_TYPE_LIVE,
175
    STREAM_TYPE_STATUS,
176
    STREAM_TYPE_REDIRECT,
177
};
178

    
179
enum IPAddressAction {
180
    IP_ALLOW = 1,
181
    IP_DENY,
182
};
183

    
184
typedef struct IPAddressACL {
185
    struct IPAddressACL *next;
186
    enum IPAddressAction action;
187
    /* These are in host order */
188
    struct in_addr first;
189
    struct in_addr last;
190
} IPAddressACL;
191

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

    
228
    /* feed specific */
229
    int feed_opened;     /* true if someone is writing to the feed */
230
    int is_feed;         /* true if it is a feed */
231
    int readonly;        /* True if writing is prohibited to the file */
232
    int conns_served;
233
    int64_t bytes_served;
234
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
235
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
236
    int64_t feed_size;          /* current size of feed */
237
    struct FFStream *next_feed;
238
} FFStream;
239

    
240
typedef struct FeedData {
241
    long long data_count;
242
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
243
} FeedData;
244

    
245
static struct sockaddr_in my_http_addr;
246
static struct sockaddr_in my_rtsp_addr;
247

    
248
static char logfilename[1024];
249
static HTTPContext *first_http_ctx;
250
static FFStream *first_feed;   /* contains only feeds */
251
static FFStream *first_stream; /* contains all streams, including feeds */
252

    
253
static void new_connection(int server_fd, int is_rtsp);
254
static void close_connection(HTTPContext *c);
255

    
256
/* HTTP handling */
257
static int handle_connection(HTTPContext *c);
258
static int http_parse_request(HTTPContext *c);
259
static int http_send_data(HTTPContext *c);
260
static void compute_status(HTTPContext *c);
261
static int open_input_stream(HTTPContext *c, const char *info);
262
static int http_start_receive_data(HTTPContext *c);
263
static int http_receive_data(HTTPContext *c);
264

    
265
/* RTSP handling */
266
static int rtsp_parse_request(HTTPContext *c);
267
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
268
static void rtsp_cmd_options(HTTPContext *c, const char *url);
269
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
270
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
271
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
272
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
273

    
274
/* SDP handling */
275
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
276
                                   struct in_addr my_ip);
277

    
278
/* RTP handling */
279
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
280
                                       FFStream *stream, const char *session_id,
281
                                       enum RTSPProtocol rtp_protocol);
282
static int rtp_new_av_stream(HTTPContext *c,
283
                             int stream_index, struct sockaddr_in *dest_addr,
284
                             HTTPContext *rtsp_c);
285

    
286
static const char *my_program_name;
287
static const char *my_program_dir;
288

    
289
static const char *config_filename;
290
static int ffserver_debug;
291
static int ffserver_daemon;
292
static int no_launch;
293
static int need_to_start_children;
294

    
295
static int nb_max_connections = 5;
296
static int nb_connections;
297

    
298
static uint64_t max_bandwidth = 1000;
299
static uint64_t current_bandwidth;
300

    
301
static int64_t cur_time;           // Making this global saves on passing it around everywhere
302

    
303
static AVRandomState random_state;
304

    
305
static FILE *logfile = NULL;
306

    
307
static char *ctime1(char *buf2)
308
{
309
    time_t ti;
310
    char *p;
311

    
312
    ti = time(NULL);
313
    p = ctime(&ti);
314
    strcpy(buf2, p);
315
    p = buf2 + strlen(p) - 1;
316
    if (*p == '\n')
317
        *p = '\0';
318
    return buf2;
319
}
320

    
321
static void http_vlog(const char *fmt, va_list vargs)
322
{
323
    static int print_prefix = 1;
324
    if (logfile) {
325
        if (print_prefix) {
326
            char buf[32];
327
            ctime1(buf);
328
            fprintf(logfile, "%s ", buf);
329
        }
330
        print_prefix = strstr(fmt, "\n") != NULL;
331
        vfprintf(logfile, fmt, vargs);
332
        fflush(logfile);
333
    }
334
}
335

    
336
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
337
{
338
    va_list vargs;
339
    va_start(vargs, fmt);
340
    http_vlog(fmt, vargs);
341
    va_end(vargs);
342
}
343

    
344
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
345
{
346
    static int print_prefix = 1;
347
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
348
    if (level > av_log_level)
349
        return;
350
    if (print_prefix && avc)
351
        http_log("[%s @ %p]", avc->item_name(ptr), avc);
352
    print_prefix = strstr(fmt, "\n") != NULL;
353
    http_vlog(fmt, vargs);
354
}
355

    
356
static void log_connection(HTTPContext *c)
357
{
358
    if (c->suppress_log)
359
        return;
360

    
361
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
362
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
363
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
364
}
365

    
366
static void update_datarate(DataRateData *drd, int64_t count)
367
{
368
    if (!drd->time1 && !drd->count1) {
369
        drd->time1 = drd->time2 = cur_time;
370
        drd->count1 = drd->count2 = count;
371
    } else if (cur_time - drd->time2 > 5000) {
372
        drd->time1 = drd->time2;
373
        drd->count1 = drd->count2;
374
        drd->time2 = cur_time;
375
        drd->count2 = count;
376
    }
377
}
378

    
379
/* In bytes per second */
380
static int compute_datarate(DataRateData *drd, int64_t count)
381
{
382
    if (cur_time == drd->time1)
383
        return 0;
384

    
385
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
386
}
387

    
388

    
389
static void start_children(FFStream *feed)
390
{
391
    if (no_launch)
392
        return;
393

    
394
    for (; feed; feed = feed->next) {
395
        if (feed->child_argv && !feed->pid) {
396
            feed->pid_start = time(0);
397

    
398
            feed->pid = fork();
399

    
400
            if (feed->pid < 0) {
401
                http_log("Unable to create children\n");
402
                exit(1);
403
            }
404
            if (!feed->pid) {
405
                /* In child */
406
                char pathname[1024];
407
                char *slash;
408
                int i;
409

    
410
                for (i = 3; i < 256; i++)
411
                    close(i);
412

    
413
                if (!ffserver_debug) {
414
                    i = open("/dev/null", O_RDWR);
415
                    if (i != -1) {
416
                        dup2(i, 0);
417
                        dup2(i, 1);
418
                        dup2(i, 2);
419
                        close(i);
420
                    }
421
                }
422

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

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

    
432
                /* This is needed to make relative pathnames work */
433
                chdir(my_program_dir);
434

    
435
                signal(SIGPIPE, SIG_DFL);
436

    
437
                execvp(pathname, feed->child_argv);
438

    
439
                _exit(1);
440
            }
441
        }
442
    }
443
}
444

    
445
/* open a listening socket */
446
static int socket_open_listen(struct sockaddr_in *my_addr)
447
{
448
    int server_fd, tmp;
449

    
450
    server_fd = socket(AF_INET,SOCK_STREAM,0);
451
    if (server_fd < 0) {
452
        perror ("socket");
453
        return -1;
454
    }
455

    
456
    tmp = 1;
457
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
458

    
459
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
460
        char bindmsg[32];
461
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
462
        perror (bindmsg);
463
        closesocket(server_fd);
464
        return -1;
465
    }
466

    
467
    if (listen (server_fd, 5) < 0) {
468
        perror ("listen");
469
        closesocket(server_fd);
470
        return -1;
471
    }
472
    ff_socket_nonblock(server_fd, 1);
473

    
474
    return server_fd;
475
}
476

    
477
/* start all multicast streams */
478
static void start_multicast(void)
479
{
480
    FFStream *stream;
481
    char session_id[32];
482
    HTTPContext *rtp_c;
483
    struct sockaddr_in dest_addr;
484
    int default_port, stream_index;
485

    
486
    default_port = 6000;
487
    for(stream = first_stream; stream != NULL; stream = stream->next) {
488
        if (stream->is_multicast) {
489
            /* open the RTP connection */
490
            snprintf(session_id, sizeof(session_id), "%08x%08x",
491
                     av_random(&random_state), av_random(&random_state));
492

    
493
            /* choose a port if none given */
494
            if (stream->multicast_port == 0) {
495
                stream->multicast_port = default_port;
496
                default_port += 100;
497
            }
498

    
499
            dest_addr.sin_family = AF_INET;
500
            dest_addr.sin_addr = stream->multicast_ip;
501
            dest_addr.sin_port = htons(stream->multicast_port);
502

    
503
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
504
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
505
            if (!rtp_c)
506
                continue;
507

    
508
            if (open_input_stream(rtp_c, "") < 0) {
509
                http_log("Could not open input stream for stream '%s'\n",
510
                         stream->filename);
511
                continue;
512
            }
513

    
514
            /* open each RTP stream */
515
            for(stream_index = 0; stream_index < stream->nb_streams;
516
                stream_index++) {
517
                dest_addr.sin_port = htons(stream->multicast_port +
518
                                           2 * stream_index);
519
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
520
                    http_log("Could not open output stream '%s/streamid=%d'\n",
521
                             stream->filename, stream_index);
522
                    exit(1);
523
                }
524
            }
525

    
526
            /* change state to send data */
527
            rtp_c->state = HTTPSTATE_SEND_DATA;
528
        }
529
    }
530
}
531

    
532
/* main loop of the http server */
533
static int http_server(void)
534
{
535
    int server_fd = 0, rtsp_server_fd = 0;
536
    int ret, delay, delay1;
537
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
538
    HTTPContext *c, *c_next;
539

    
540
    if (my_http_addr.sin_port) {
541
        server_fd = socket_open_listen(&my_http_addr);
542
        if (server_fd < 0)
543
            return -1;
544
    }
545

    
546
    if (my_rtsp_addr.sin_port) {
547
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
548
        if (rtsp_server_fd < 0)
549
            return -1;
550
    }
551

    
552
    if (!rtsp_server_fd && !server_fd) {
553
        http_log("HTTP and RTSP disabled.\n");
554
        return -1;
555
    }
556

    
557
    http_log("ffserver started.\n");
558

    
559
    start_children(first_feed);
560

    
561
    first_http_ctx = NULL;
562
    nb_connections = 0;
563

    
564
    start_multicast();
565

    
566
    for(;;) {
567
        poll_entry = poll_table;
568
        if (server_fd) {
569
            poll_entry->fd = server_fd;
570
            poll_entry->events = POLLIN;
571
            poll_entry++;
572
        }
573
        if (rtsp_server_fd) {
574
            poll_entry->fd = rtsp_server_fd;
575
            poll_entry->events = POLLIN;
576
            poll_entry++;
577
        }
578

    
579
        /* wait for events on each HTTP handle */
580
        c = first_http_ctx;
581
        delay = 1000;
582
        while (c != NULL) {
583
            int fd;
584
            fd = c->fd;
585
            switch(c->state) {
586
            case HTTPSTATE_SEND_HEADER:
587
            case RTSPSTATE_SEND_REPLY:
588
            case RTSPSTATE_SEND_PACKET:
589
                c->poll_entry = poll_entry;
590
                poll_entry->fd = fd;
591
                poll_entry->events = POLLOUT;
592
                poll_entry++;
593
                break;
594
            case HTTPSTATE_SEND_DATA_HEADER:
595
            case HTTPSTATE_SEND_DATA:
596
            case HTTPSTATE_SEND_DATA_TRAILER:
597
                if (!c->is_packetized) {
598
                    /* for TCP, we output as much as we can (may need to put a limit) */
599
                    c->poll_entry = poll_entry;
600
                    poll_entry->fd = fd;
601
                    poll_entry->events = POLLOUT;
602
                    poll_entry++;
603
                } else {
604
                    /* when ffserver is doing the timing, we work by
605
                       looking at which packet need to be sent every
606
                       10 ms */
607
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
608
                    if (delay1 < delay)
609
                        delay = delay1;
610
                }
611
                break;
612
            case HTTPSTATE_WAIT_REQUEST:
613
            case HTTPSTATE_RECEIVE_DATA:
614
            case HTTPSTATE_WAIT_FEED:
615
            case RTSPSTATE_WAIT_REQUEST:
616
                /* need to catch errors */
617
                c->poll_entry = poll_entry;
618
                poll_entry->fd = fd;
619
                poll_entry->events = POLLIN;/* Maybe this will work */
620
                poll_entry++;
621
                break;
622
            default:
623
                c->poll_entry = NULL;
624
                break;
625
            }
626
            c = c->next;
627
        }
628

    
629
        /* wait for an event on one connection. We poll at least every
630
           second to handle timeouts */
631
        do {
632
            ret = poll(poll_table, poll_entry - poll_table, delay);
633
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
634
                ff_neterrno() != FF_NETERROR(EINTR))
635
                return -1;
636
        } while (ret < 0);
637

    
638
        cur_time = av_gettime() / 1000;
639

    
640
        if (need_to_start_children) {
641
            need_to_start_children = 0;
642
            start_children(first_feed);
643
        }
644

    
645
        /* now handle the events */
646
        for(c = first_http_ctx; c != NULL; c = c_next) {
647
            c_next = c->next;
648
            if (handle_connection(c) < 0) {
649
                /* close and free the connection */
650
                log_connection(c);
651
                close_connection(c);
652
            }
653
        }
654

    
655
        poll_entry = poll_table;
656
        if (server_fd) {
657
            /* new HTTP connection request ? */
658
            if (poll_entry->revents & POLLIN)
659
                new_connection(server_fd, 0);
660
            poll_entry++;
661
        }
662
        if (rtsp_server_fd) {
663
            /* new RTSP connection request ? */
664
            if (poll_entry->revents & POLLIN)
665
                new_connection(rtsp_server_fd, 1);
666
        }
667
    }
668
}
669

    
670
/* start waiting for a new HTTP/RTSP request */
671
static void start_wait_request(HTTPContext *c, int is_rtsp)
672
{
673
    c->buffer_ptr = c->buffer;
674
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
675

    
676
    if (is_rtsp) {
677
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
678
        c->state = RTSPSTATE_WAIT_REQUEST;
679
    } else {
680
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
681
        c->state = HTTPSTATE_WAIT_REQUEST;
682
    }
683
}
684

    
685
static void new_connection(int server_fd, int is_rtsp)
686
{
687
    struct sockaddr_in from_addr;
688
    int fd, len;
689
    HTTPContext *c = NULL;
690

    
691
    len = sizeof(from_addr);
692
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
693
                &len);
694
    if (fd < 0) {
695
        http_log("error during accept %s\n", strerror(errno));
696
        return;
697
    }
698
    ff_socket_nonblock(fd, 1);
699

    
700
    /* XXX: should output a warning page when coming
701
       close to the connection limit */
702
    if (nb_connections >= nb_max_connections)
703
        goto fail;
704

    
705
    /* add a new connection */
706
    c = av_mallocz(sizeof(HTTPContext));
707
    if (!c)
708
        goto fail;
709

    
710
    c->fd = fd;
711
    c->poll_entry = NULL;
712
    c->from_addr = from_addr;
713
    c->buffer_size = IOBUFFER_INIT_SIZE;
714
    c->buffer = av_malloc(c->buffer_size);
715
    if (!c->buffer)
716
        goto fail;
717

    
718
    c->next = first_http_ctx;
719
    first_http_ctx = c;
720
    nb_connections++;
721

    
722
    start_wait_request(c, is_rtsp);
723

    
724
    return;
725

    
726
 fail:
727
    if (c) {
728
        av_free(c->buffer);
729
        av_free(c);
730
    }
731
    closesocket(fd);
732
}
733

    
734
static void close_connection(HTTPContext *c)
735
{
736
    HTTPContext **cp, *c1;
737
    int i, nb_streams;
738
    AVFormatContext *ctx;
739
    URLContext *h;
740
    AVStream *st;
741

    
742
    /* remove connection from list */
743
    cp = &first_http_ctx;
744
    while ((*cp) != NULL) {
745
        c1 = *cp;
746
        if (c1 == c)
747
            *cp = c->next;
748
        else
749
            cp = &c1->next;
750
    }
751

    
752
    /* remove references, if any (XXX: do it faster) */
753
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
754
        if (c1->rtsp_c == c)
755
            c1->rtsp_c = NULL;
756
    }
757

    
758
    /* remove connection associated resources */
759
    if (c->fd >= 0)
760
        closesocket(c->fd);
761
    if (c->fmt_in) {
762
        /* close each frame parser */
763
        for(i=0;i<c->fmt_in->nb_streams;i++) {
764
            st = c->fmt_in->streams[i];
765
            if (st->codec->codec)
766
                avcodec_close(st->codec);
767
        }
768
        av_close_input_file(c->fmt_in);
769
    }
770

    
771
    /* free RTP output streams if any */
772
    nb_streams = 0;
773
    if (c->stream)
774
        nb_streams = c->stream->nb_streams;
775

    
776
    for(i=0;i<nb_streams;i++) {
777
        ctx = c->rtp_ctx[i];
778
        if (ctx) {
779
            av_write_trailer(ctx);
780
            av_free(ctx);
781
        }
782
        h = c->rtp_handles[i];
783
        if (h)
784
            url_close(h);
785
    }
786

    
787
    ctx = &c->fmt_ctx;
788

    
789
    if (!c->last_packet_sent) {
790
        if (ctx->oformat) {
791
            /* prepare header */
792
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
793
                av_write_trailer(ctx);
794
                av_freep(&c->pb_buffer);
795
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
796
            }
797
        }
798
    }
799

    
800
    for(i=0; i<ctx->nb_streams; i++)
801
        av_free(ctx->streams[i]);
802

    
803
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
804
        current_bandwidth -= c->stream->bandwidth;
805

    
806
    /* signal that there is no feed if we are the feeder socket */
807
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
808
        c->stream->feed_opened = 0;
809
        close(c->feed_fd);
810
    }
811

    
812
    av_freep(&c->pb_buffer);
813
    av_freep(&c->packet_buffer);
814
    av_free(c->buffer);
815
    av_free(c);
816
    nb_connections--;
817
}
818

    
819
static int handle_connection(HTTPContext *c)
820
{
821
    int len, ret;
822

    
823
    switch(c->state) {
824
    case HTTPSTATE_WAIT_REQUEST:
825
    case RTSPSTATE_WAIT_REQUEST:
826
        /* timeout ? */
827
        if ((c->timeout - cur_time) < 0)
828
            return -1;
829
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
830
            return -1;
831

    
832
        /* no need to read if no events */
833
        if (!(c->poll_entry->revents & POLLIN))
834
            return 0;
835
        /* read the data */
836
    read_loop:
837
        len = recv(c->fd, c->buffer_ptr, 1, 0);
838
        if (len < 0) {
839
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
840
                ff_neterrno() != FF_NETERROR(EINTR))
841
                return -1;
842
        } else if (len == 0) {
843
            return -1;
844
        } else {
845
            /* search for end of request. */
846
            uint8_t *ptr;
847
            c->buffer_ptr += len;
848
            ptr = c->buffer_ptr;
849
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
850
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
851
                /* request found : parse it and reply */
852
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
853
                    ret = http_parse_request(c);
854
                } else {
855
                    ret = rtsp_parse_request(c);
856
                }
857
                if (ret < 0)
858
                    return -1;
859
            } else if (ptr >= c->buffer_end) {
860
                /* request too long: cannot do anything */
861
                return -1;
862
            } else goto read_loop;
863
        }
864
        break;
865

    
866
    case HTTPSTATE_SEND_HEADER:
867
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
868
            return -1;
869

    
870
        /* no need to write if no events */
871
        if (!(c->poll_entry->revents & POLLOUT))
872
            return 0;
873
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
874
        if (len < 0) {
875
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
876
                ff_neterrno() != FF_NETERROR(EINTR)) {
877
                /* error : close connection */
878
                av_freep(&c->pb_buffer);
879
                return -1;
880
            }
881
        } else {
882
            c->buffer_ptr += len;
883
            if (c->stream)
884
                c->stream->bytes_served += len;
885
            c->data_count += len;
886
            if (c->buffer_ptr >= c->buffer_end) {
887
                av_freep(&c->pb_buffer);
888
                /* if error, exit */
889
                if (c->http_error)
890
                    return -1;
891
                /* all the buffer was sent : synchronize to the incoming stream */
892
                c->state = HTTPSTATE_SEND_DATA_HEADER;
893
                c->buffer_ptr = c->buffer_end = c->buffer;
894
            }
895
        }
896
        break;
897

    
898
    case HTTPSTATE_SEND_DATA:
899
    case HTTPSTATE_SEND_DATA_HEADER:
900
    case HTTPSTATE_SEND_DATA_TRAILER:
901
        /* for packetized output, we consider we can always write (the
902
           input streams sets the speed). It may be better to verify
903
           that we do not rely too much on the kernel queues */
904
        if (!c->is_packetized) {
905
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
906
                return -1;
907

    
908
            /* no need to read if no events */
909
            if (!(c->poll_entry->revents & POLLOUT))
910
                return 0;
911
        }
912
        if (http_send_data(c) < 0)
913
            return -1;
914
        /* close connection if trailer sent */
915
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
916
            return -1;
917
        break;
918
    case HTTPSTATE_RECEIVE_DATA:
919
        /* no need to read if no events */
920
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
921
            return -1;
922
        if (!(c->poll_entry->revents & POLLIN))
923
            return 0;
924
        if (http_receive_data(c) < 0)
925
            return -1;
926
        break;
927
    case HTTPSTATE_WAIT_FEED:
928
        /* no need to read if no events */
929
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
930
            return -1;
931

    
932
        /* nothing to do, we'll be waken up by incoming feed packets */
933
        break;
934

    
935
    case RTSPSTATE_SEND_REPLY:
936
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
937
            av_freep(&c->pb_buffer);
938
            return -1;
939
        }
940
        /* no need to write if no events */
941
        if (!(c->poll_entry->revents & POLLOUT))
942
            return 0;
943
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
944
        if (len < 0) {
945
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
946
                ff_neterrno() != FF_NETERROR(EINTR)) {
947
                /* error : close connection */
948
                av_freep(&c->pb_buffer);
949
                return -1;
950
            }
951
        } else {
952
            c->buffer_ptr += len;
953
            c->data_count += len;
954
            if (c->buffer_ptr >= c->buffer_end) {
955
                /* all the buffer was sent : wait for a new request */
956
                av_freep(&c->pb_buffer);
957
                start_wait_request(c, 1);
958
            }
959
        }
960
        break;
961
    case RTSPSTATE_SEND_PACKET:
962
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
963
            av_freep(&c->packet_buffer);
964
            return -1;
965
        }
966
        /* no need to write if no events */
967
        if (!(c->poll_entry->revents & POLLOUT))
968
            return 0;
969
        len = send(c->fd, c->packet_buffer_ptr,
970
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
971
        if (len < 0) {
972
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
973
                ff_neterrno() != FF_NETERROR(EINTR)) {
974
                /* error : close connection */
975
                av_freep(&c->packet_buffer);
976
                return -1;
977
            }
978
        } else {
979
            c->packet_buffer_ptr += len;
980
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
981
                /* all the buffer was sent : wait for a new request */
982
                av_freep(&c->packet_buffer);
983
                c->state = RTSPSTATE_WAIT_REQUEST;
984
            }
985
        }
986
        break;
987
    case HTTPSTATE_READY:
988
        /* nothing to do */
989
        break;
990
    default:
991
        return -1;
992
    }
993
    return 0;
994
}
995

    
996
static int extract_rates(char *rates, int ratelen, const char *request)
997
{
998
    const char *p;
999

    
1000
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1001
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1002
            const char *q = p + 7;
1003

    
1004
            while (*q && *q != '\n' && isspace(*q))
1005
                q++;
1006

    
1007
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1008
                int stream_no;
1009
                int rate_no;
1010

    
1011
                q += 20;
1012

    
1013
                memset(rates, 0xff, ratelen);
1014

    
1015
                while (1) {
1016
                    while (*q && *q != '\n' && *q != ':')
1017
                        q++;
1018

    
1019
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1020
                        break;
1021

    
1022
                    stream_no--;
1023
                    if (stream_no < ratelen && stream_no >= 0)
1024
                        rates[stream_no] = rate_no;
1025

    
1026
                    while (*q && *q != '\n' && !isspace(*q))
1027
                        q++;
1028
                }
1029

    
1030
                return 1;
1031
            }
1032
        }
1033
        p = strchr(p, '\n');
1034
        if (!p)
1035
            break;
1036

    
1037
        p++;
1038
    }
1039

    
1040
    return 0;
1041
}
1042

    
1043
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1044
{
1045
    int i;
1046
    int best_bitrate = 100000000;
1047
    int best = -1;
1048

    
1049
    for (i = 0; i < feed->nb_streams; i++) {
1050
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1051

    
1052
        if (feed_codec->codec_id != codec->codec_id ||
1053
            feed_codec->sample_rate != codec->sample_rate ||
1054
            feed_codec->width != codec->width ||
1055
            feed_codec->height != codec->height)
1056
            continue;
1057

    
1058
        /* Potential stream */
1059

    
1060
        /* We want the fastest stream less than bit_rate, or the slowest
1061
         * faster than bit_rate
1062
         */
1063

    
1064
        if (feed_codec->bit_rate <= bit_rate) {
1065
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1066
                best_bitrate = feed_codec->bit_rate;
1067
                best = i;
1068
            }
1069
        } else {
1070
            if (feed_codec->bit_rate < best_bitrate) {
1071
                best_bitrate = feed_codec->bit_rate;
1072
                best = i;
1073
            }
1074
        }
1075
    }
1076

    
1077
    return best;
1078
}
1079

    
1080
static int modify_current_stream(HTTPContext *c, char *rates)
1081
{
1082
    int i;
1083
    FFStream *req = c->stream;
1084
    int action_required = 0;
1085

    
1086
    /* Not much we can do for a feed */
1087
    if (!req->feed)
1088
        return 0;
1089

    
1090
    for (i = 0; i < req->nb_streams; i++) {
1091
        AVCodecContext *codec = req->streams[i]->codec;
1092

    
1093
        switch(rates[i]) {
1094
            case 0:
1095
                c->switch_feed_streams[i] = req->feed_streams[i];
1096
                break;
1097
            case 1:
1098
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1099
                break;
1100
            case 2:
1101
                /* Wants off or slow */
1102
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1103
#ifdef WANTS_OFF
1104
                /* This doesn't work well when it turns off the only stream! */
1105
                c->switch_feed_streams[i] = -2;
1106
                c->feed_streams[i] = -2;
1107
#endif
1108
                break;
1109
        }
1110

    
1111
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1112
            action_required = 1;
1113
    }
1114

    
1115
    return action_required;
1116
}
1117

    
1118

    
1119
static void do_switch_stream(HTTPContext *c, int i)
1120
{
1121
    if (c->switch_feed_streams[i] >= 0) {
1122
#ifdef PHILIP
1123
        c->feed_streams[i] = c->switch_feed_streams[i];
1124
#endif
1125

    
1126
        /* Now update the stream */
1127
    }
1128
    c->switch_feed_streams[i] = -1;
1129
}
1130

    
1131
/* XXX: factorize in utils.c ? */
1132
/* XXX: take care with different space meaning */
1133
static void skip_spaces(const char **pp)
1134
{
1135
    const char *p;
1136
    p = *pp;
1137
    while (*p == ' ' || *p == '\t')
1138
        p++;
1139
    *pp = p;
1140
}
1141

    
1142
static void get_word(char *buf, int buf_size, const char **pp)
1143
{
1144
    const char *p;
1145
    char *q;
1146

    
1147
    p = *pp;
1148
    skip_spaces(&p);
1149
    q = buf;
1150
    while (!isspace(*p) && *p != '\0') {
1151
        if ((q - buf) < buf_size - 1)
1152
            *q++ = *p;
1153
        p++;
1154
    }
1155
    if (buf_size > 0)
1156
        *q = '\0';
1157
    *pp = p;
1158
}
1159

    
1160
static int validate_acl(FFStream *stream, HTTPContext *c)
1161
{
1162
    enum IPAddressAction last_action = IP_DENY;
1163
    IPAddressACL *acl;
1164
    struct in_addr *src = &c->from_addr.sin_addr;
1165
    unsigned long src_addr = src->s_addr;
1166

    
1167
    for (acl = stream->acl; acl; acl = acl->next) {
1168
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1169
            return (acl->action == IP_ALLOW) ? 1 : 0;
1170
        last_action = acl->action;
1171
    }
1172

    
1173
    /* Nothing matched, so return not the last action */
1174
    return (last_action == IP_DENY) ? 1 : 0;
1175
}
1176

    
1177
/* compute the real filename of a file by matching it without its
1178
   extensions to all the stream filenames */
1179
static void compute_real_filename(char *filename, int max_size)
1180
{
1181
    char file1[1024];
1182
    char file2[1024];
1183
    char *p;
1184
    FFStream *stream;
1185

    
1186
    /* compute filename by matching without the file extensions */
1187
    av_strlcpy(file1, filename, sizeof(file1));
1188
    p = strrchr(file1, '.');
1189
    if (p)
1190
        *p = '\0';
1191
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1192
        av_strlcpy(file2, stream->filename, sizeof(file2));
1193
        p = strrchr(file2, '.');
1194
        if (p)
1195
            *p = '\0';
1196
        if (!strcmp(file1, file2)) {
1197
            av_strlcpy(filename, stream->filename, max_size);
1198
            break;
1199
        }
1200
    }
1201
}
1202

    
1203
enum RedirType {
1204
    REDIR_NONE,
1205
    REDIR_ASX,
1206
    REDIR_RAM,
1207
    REDIR_ASF,
1208
    REDIR_RTSP,
1209
    REDIR_SDP,
1210
};
1211

    
1212
/* parse http request and prepare header */
1213
static int http_parse_request(HTTPContext *c)
1214
{
1215
    char *p;
1216
    enum RedirType redir_type;
1217
    char cmd[32];
1218
    char info[1024], filename[1024];
1219
    char url[1024], *q;
1220
    char protocol[32];
1221
    char msg[1024];
1222
    const char *mime_type;
1223
    FFStream *stream;
1224
    int i;
1225
    char ratebuf[32];
1226
    char *useragent = 0;
1227

    
1228
    p = c->buffer;
1229
    get_word(cmd, sizeof(cmd), (const char **)&p);
1230
    av_strlcpy(c->method, cmd, sizeof(c->method));
1231

    
1232
    if (!strcmp(cmd, "GET"))
1233
        c->post = 0;
1234
    else if (!strcmp(cmd, "POST"))
1235
        c->post = 1;
1236
    else
1237
        return -1;
1238

    
1239
    get_word(url, sizeof(url), (const char **)&p);
1240
    av_strlcpy(c->url, url, sizeof(c->url));
1241

    
1242
    get_word(protocol, sizeof(protocol), (const char **)&p);
1243
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1244
        return -1;
1245

    
1246
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1247

    
1248
    if (ffserver_debug)
1249
        http_log("New connection: %s %s\n", cmd, url);
1250

    
1251
    /* find the filename and the optional info string in the request */
1252
    p = strchr(url, '?');
1253
    if (p) {
1254
        av_strlcpy(info, p, sizeof(info));
1255
        *p = '\0';
1256
    } else
1257
        info[0] = '\0';
1258

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

    
1261
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1262
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1263
            useragent = p + 11;
1264
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1265
                useragent++;
1266
            break;
1267
        }
1268
        p = strchr(p, '\n');
1269
        if (!p)
1270
            break;
1271

    
1272
        p++;
1273
    }
1274

    
1275
    redir_type = REDIR_NONE;
1276
    if (match_ext(filename, "asx")) {
1277
        redir_type = REDIR_ASX;
1278
        filename[strlen(filename)-1] = 'f';
1279
    } else if (match_ext(filename, "asf") &&
1280
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1281
        /* if this isn't WMP or lookalike, return the redirector file */
1282
        redir_type = REDIR_ASF;
1283
    } else if (match_ext(filename, "rpm,ram")) {
1284
        redir_type = REDIR_RAM;
1285
        strcpy(filename + strlen(filename)-2, "m");
1286
    } else if (match_ext(filename, "rtsp")) {
1287
        redir_type = REDIR_RTSP;
1288
        compute_real_filename(filename, sizeof(filename) - 1);
1289
    } else if (match_ext(filename, "sdp")) {
1290
        redir_type = REDIR_SDP;
1291
        compute_real_filename(filename, sizeof(filename) - 1);
1292
    }
1293

    
1294
    // "redirect" / request to index.html
1295
    if (!strlen(filename))
1296
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1297

    
1298
    stream = first_stream;
1299
    while (stream != NULL) {
1300
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1301
            break;
1302
        stream = stream->next;
1303
    }
1304
    if (stream == NULL) {
1305
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1306
        goto send_error;
1307
    }
1308

    
1309
    c->stream = stream;
1310
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1311
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1312

    
1313
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1314
        c->http_error = 301;
1315
        q = c->buffer;
1316
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1322
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1323

    
1324
        /* prepare output buffer */
1325
        c->buffer_ptr = c->buffer;
1326
        c->buffer_end = q;
1327
        c->state = HTTPSTATE_SEND_HEADER;
1328
        return 0;
1329
    }
1330

    
1331
    /* If this is WMP, get the rate information */
1332
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1333
        if (modify_current_stream(c, ratebuf)) {
1334
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1335
                if (c->switch_feed_streams[i] >= 0)
1336
                    do_switch_stream(c, i);
1337
            }
1338
        }
1339
    }
1340

    
1341
    /* If already streaming this feed, do not let start another feeder. */
1342
    if (stream->feed_opened) {
1343
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1344
        goto send_error;
1345
    }
1346

    
1347
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1348
        current_bandwidth += stream->bandwidth;
1349

    
1350
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1351
        c->http_error = 200;
1352
        q = c->buffer;
1353
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1354
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1355
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1356
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1357
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1358
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
1359
            current_bandwidth, max_bandwidth);
1360
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1361

    
1362
        /* prepare output buffer */
1363
        c->buffer_ptr = c->buffer;
1364
        c->buffer_end = q;
1365
        c->state = HTTPSTATE_SEND_HEADER;
1366
        return 0;
1367
    }
1368

    
1369
    if (redir_type != REDIR_NONE) {
1370
        char *hostinfo = 0;
1371

    
1372
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1373
            if (strncasecmp(p, "Host:", 5) == 0) {
1374
                hostinfo = p + 5;
1375
                break;
1376
            }
1377
            p = strchr(p, '\n');
1378
            if (!p)
1379
                break;
1380

    
1381
            p++;
1382
        }
1383

    
1384
        if (hostinfo) {
1385
            char *eoh;
1386
            char hostbuf[260];
1387

    
1388
            while (isspace(*hostinfo))
1389
                hostinfo++;
1390

    
1391
            eoh = strchr(hostinfo, '\n');
1392
            if (eoh) {
1393
                if (eoh[-1] == '\r')
1394
                    eoh--;
1395

    
1396
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1397
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1398
                    hostbuf[eoh - hostinfo] = 0;
1399

    
1400
                    c->http_error = 200;
1401
                    q = c->buffer;
1402
                    switch(redir_type) {
1403
                    case REDIR_ASX:
1404
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
1405
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1406
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1407
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
1408
                        //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
1409
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1410
                                hostbuf, filename, info);
1411
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
1412
                        break;
1413
                    case REDIR_RAM:
1414
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
1415
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
1416
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1417
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
1418
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
1419
                                hostbuf, filename, info);
1420
                        break;
1421
                    case REDIR_ASF:
1422
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
1423
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1424
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1425
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
1426
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
1427
                                hostbuf, filename, info);
1428
                        break;
1429
                    case REDIR_RTSP:
1430
                        {
1431
                            char hostname[256], *p;
1432
                            /* extract only hostname */
1433
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1434
                            p = strrchr(hostname, ':');
1435
                            if (p)
1436
                                *p = '\0';
1437
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1438
                            /* XXX: incorrect mime type ? */
1439
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
1440
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1441
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
1442
                                         hostname, ntohs(my_rtsp_addr.sin_port),
1443
                                         filename);
1444
                        }
1445
                        break;
1446
                    case REDIR_SDP:
1447
                        {
1448
                            uint8_t *sdp_data;
1449
                            int sdp_data_size, len;
1450
                            struct sockaddr_in my_addr;
1451

    
1452
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1453
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1454
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1455

    
1456
                            len = sizeof(my_addr);
1457
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1458

    
1459
                            /* XXX: should use a dynamic buffer */
1460
                            sdp_data_size = prepare_sdp_description(stream,
1461
                                                                    &sdp_data,
1462
                                                                    my_addr.sin_addr);
1463
                            if (sdp_data_size > 0) {
1464
                                memcpy(q, sdp_data, sdp_data_size);
1465
                                q += sdp_data_size;
1466
                                *q = '\0';
1467
                                av_free(sdp_data);
1468
                            }
1469
                        }
1470
                        break;
1471
                    default:
1472
                        abort();
1473
                        break;
1474
                    }
1475

    
1476
                    /* prepare output buffer */
1477
                    c->buffer_ptr = c->buffer;
1478
                    c->buffer_end = q;
1479
                    c->state = HTTPSTATE_SEND_HEADER;
1480
                    return 0;
1481
                }
1482
            }
1483
        }
1484

    
1485
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1486
        goto send_error;
1487
    }
1488

    
1489
    stream->conns_served++;
1490

    
1491
    /* XXX: add there authenticate and IP match */
1492

    
1493
    if (c->post) {
1494
        /* if post, it means a feed is being sent */
1495
        if (!stream->is_feed) {
1496
            /* However it might be a status report from WMP! Lets log the data
1497
             * as it might come in handy one day
1498
             */
1499
            char *logline = 0;
1500
            int client_id = 0;
1501

    
1502
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1503
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1504
                    logline = p;
1505
                    break;
1506
                }
1507
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1508
                    client_id = strtol(p + 18, 0, 10);
1509
                p = strchr(p, '\n');
1510
                if (!p)
1511
                    break;
1512

    
1513
                p++;
1514
            }
1515

    
1516
            if (logline) {
1517
                char *eol = strchr(logline, '\n');
1518

    
1519
                logline += 17;
1520

    
1521
                if (eol) {
1522
                    if (eol[-1] == '\r')
1523
                        eol--;
1524
                    http_log("%.*s\n", (int) (eol - logline), logline);
1525
                    c->suppress_log = 1;
1526
                }
1527
            }
1528

    
1529
#ifdef DEBUG_WMP
1530
            http_log("\nGot request:\n%s\n", c->buffer);
1531
#endif
1532

    
1533
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1534
                HTTPContext *wmpc;
1535

    
1536
                /* Now we have to find the client_id */
1537
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1538
                    if (wmpc->wmp_client_id == client_id)
1539
                        break;
1540
                }
1541

    
1542
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1543
                    wmpc->switch_pending = 1;
1544
            }
1545

    
1546
            snprintf(msg, sizeof(msg), "POST command not handled");
1547
            c->stream = 0;
1548
            goto send_error;
1549
        }
1550
        if (http_start_receive_data(c) < 0) {
1551
            snprintf(msg, sizeof(msg), "could not open feed");
1552
            goto send_error;
1553
        }
1554
        c->http_error = 0;
1555
        c->state = HTTPSTATE_RECEIVE_DATA;
1556
        return 0;
1557
    }
1558

    
1559
#ifdef DEBUG_WMP
1560
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1561
        http_log("\nGot request:\n%s\n", c->buffer);
1562
#endif
1563

    
1564
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1565
        goto send_status;
1566

    
1567
    /* open input stream */
1568
    if (open_input_stream(c, info) < 0) {
1569
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1570
        goto send_error;
1571
    }
1572

    
1573
    /* prepare http header */
1574
    q = c->buffer;
1575
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1576
    mime_type = c->stream->fmt->mime_type;
1577
    if (!mime_type)
1578
        mime_type = "application/x-octet-stream";
1579
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1580

    
1581
    /* for asf, we need extra headers */
1582
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1583
        /* Need to allocate a client id */
1584

    
1585
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1586

    
1587
        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);
1588
    }
1589
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1590
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1591

    
1592
    /* prepare output buffer */
1593
    c->http_error = 0;
1594
    c->buffer_ptr = c->buffer;
1595
    c->buffer_end = q;
1596
    c->state = HTTPSTATE_SEND_HEADER;
1597
    return 0;
1598
 send_error:
1599
    c->http_error = 404;
1600
    q = c->buffer;
1601
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1602
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1603
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1604
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1605
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1606
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1607
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1608

    
1609
    /* prepare output buffer */
1610
    c->buffer_ptr = c->buffer;
1611
    c->buffer_end = q;
1612
    c->state = HTTPSTATE_SEND_HEADER;
1613
    return 0;
1614
 send_status:
1615
    compute_status(c);
1616
    c->http_error = 200; /* horrible : we use this value to avoid
1617
                            going to the send data state */
1618
    c->state = HTTPSTATE_SEND_HEADER;
1619
    return 0;
1620
}
1621

    
1622
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1623
{
1624
    static const char *suffix = " kMGTP";
1625
    const char *s;
1626

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

    
1629
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1630
}
1631

    
1632
static void compute_status(HTTPContext *c)
1633
{
1634
    HTTPContext *c1;
1635
    FFStream *stream;
1636
    char *p;
1637
    time_t ti;
1638
    int i, len;
1639
    ByteIOContext *pb;
1640

    
1641
    if (url_open_dyn_buf(&pb) < 0) {
1642
        /* XXX: return an error ? */
1643
        c->buffer_ptr = c->buffer;
1644
        c->buffer_end = c->buffer;
1645
        return;
1646
    }
1647

    
1648
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1649
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1650
    url_fprintf(pb, "Pragma: no-cache\r\n");
1651
    url_fprintf(pb, "\r\n");
1652

    
1653
    url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
1654
    if (c->stream->feed_filename[0])
1655
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1656
    url_fprintf(pb, "</HEAD>\n<BODY>");
1657
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1658
    /* format status */
1659
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1660
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1661
    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");
1662
    stream = first_stream;
1663
    while (stream != NULL) {
1664
        char sfilename[1024];
1665
        char *eosf;
1666

    
1667
        if (stream->feed != stream) {
1668
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1669
            eosf = sfilename + strlen(sfilename);
1670
            if (eosf - sfilename >= 4) {
1671
                if (strcmp(eosf - 4, ".asf") == 0)
1672
                    strcpy(eosf - 4, ".asx");
1673
                else if (strcmp(eosf - 3, ".rm") == 0)
1674
                    strcpy(eosf - 3, ".ram");
1675
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1676
                    /* generate a sample RTSP director if
1677
                       unicast. Generate an SDP redirector if
1678
                       multicast */
1679
                    eosf = strrchr(sfilename, '.');
1680
                    if (!eosf)
1681
                        eosf = sfilename + strlen(sfilename);
1682
                    if (stream->is_multicast)
1683
                        strcpy(eosf, ".sdp");
1684
                    else
1685
                        strcpy(eosf, ".rtsp");
1686
                }
1687
            }
1688

    
1689
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1690
                         sfilename, stream->filename);
1691
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1692
                        stream->conns_served);
1693
            fmt_bytecount(pb, stream->bytes_served);
1694
            switch(stream->stream_type) {
1695
            case STREAM_TYPE_LIVE:
1696
                {
1697
                    int audio_bit_rate = 0;
1698
                    int video_bit_rate = 0;
1699
                    const char *audio_codec_name = "";
1700
                    const char *video_codec_name = "";
1701
                    const char *audio_codec_name_extra = "";
1702
                    const char *video_codec_name_extra = "";
1703

    
1704
                    for(i=0;i<stream->nb_streams;i++) {
1705
                        AVStream *st = stream->streams[i];
1706
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1707
                        switch(st->codec->codec_type) {
1708
                        case CODEC_TYPE_AUDIO:
1709
                            audio_bit_rate += st->codec->bit_rate;
1710
                            if (codec) {
1711
                                if (*audio_codec_name)
1712
                                    audio_codec_name_extra = "...";
1713
                                audio_codec_name = codec->name;
1714
                            }
1715
                            break;
1716
                        case CODEC_TYPE_VIDEO:
1717
                            video_bit_rate += st->codec->bit_rate;
1718
                            if (codec) {
1719
                                if (*video_codec_name)
1720
                                    video_codec_name_extra = "...";
1721
                                video_codec_name = codec->name;
1722
                            }
1723
                            break;
1724
                        case CODEC_TYPE_DATA:
1725
                            video_bit_rate += st->codec->bit_rate;
1726
                            break;
1727
                        default:
1728
                            abort();
1729
                        }
1730
                    }
1731
                    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",
1732
                                 stream->fmt->name,
1733
                                 stream->bandwidth,
1734
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1735
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1736
                    if (stream->feed)
1737
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1738
                    else
1739
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1740
                    url_fprintf(pb, "\n");
1741
                }
1742
                break;
1743
            default:
1744
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1745
                break;
1746
            }
1747
        }
1748
        stream = stream->next;
1749
    }
1750
    url_fprintf(pb, "</TABLE>\n");
1751

    
1752
    stream = first_stream;
1753
    while (stream != NULL) {
1754
        if (stream->feed == stream) {
1755
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1756
            if (stream->pid) {
1757
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1758

    
1759
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1760
                {
1761
                    FILE *pid_stat;
1762
                    char ps_cmd[64];
1763

    
1764
                    /* This is somewhat linux specific I guess */
1765
                    snprintf(ps_cmd, sizeof(ps_cmd),
1766
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1767
                             stream->pid);
1768

    
1769
                    pid_stat = popen(ps_cmd, "r");
1770
                    if (pid_stat) {
1771
                        char cpuperc[10];
1772
                        char cpuused[64];
1773

    
1774
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1775
                                   cpuused) == 2) {
1776
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1777
                                         cpuperc, cpuused);
1778
                        }
1779
                        fclose(pid_stat);
1780
                    }
1781
                }
1782
#endif
1783

    
1784
                url_fprintf(pb, "<p>");
1785
            }
1786
            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");
1787

    
1788
            for (i = 0; i < stream->nb_streams; i++) {
1789
                AVStream *st = stream->streams[i];
1790
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1791
                const char *type = "unknown";
1792
                char parameters[64];
1793

    
1794
                parameters[0] = 0;
1795

    
1796
                switch(st->codec->codec_type) {
1797
                case CODEC_TYPE_AUDIO:
1798
                    type = "audio";
1799
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1800
                    break;
1801
                case CODEC_TYPE_VIDEO:
1802
                    type = "video";
1803
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1804
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1805
                    break;
1806
                default:
1807
                    abort();
1808
                }
1809
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1810
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1811
            }
1812
            url_fprintf(pb, "</table>\n");
1813

    
1814
        }
1815
        stream = stream->next;
1816
    }
1817

    
1818
#if 0
1819
    {
1820
        float avg;
1821
        AVCodecContext *enc;
1822
        char buf[1024];
1823

1824
        /* feed status */
1825
        stream = first_feed;
1826
        while (stream != NULL) {
1827
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1828
            url_fprintf(pb, "<TABLE>\n");
1829
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1830
            for(i=0;i<stream->nb_streams;i++) {
1831
                AVStream *st = stream->streams[i];
1832
                FeedData *fdata = st->priv_data;
1833
                enc = st->codec;
1834

1835
                avcodec_string(buf, sizeof(buf), enc);
1836
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1837
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1838
                    avg /= enc->frame_size;
1839
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1840
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1841
            }
1842
            url_fprintf(pb, "</TABLE>\n");
1843
            stream = stream->next_feed;
1844
        }
1845
    }
1846
#endif
1847

    
1848
    /* connection status */
1849
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1850

    
1851
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1852
                 nb_connections, nb_max_connections);
1853

    
1854
    url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
1855
                 current_bandwidth, max_bandwidth);
1856

    
1857
    url_fprintf(pb, "<TABLE>\n");
1858
    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");
1859
    c1 = first_http_ctx;
1860
    i = 0;
1861
    while (c1 != NULL) {
1862
        int bitrate;
1863
        int j;
1864

    
1865
        bitrate = 0;
1866
        if (c1->stream) {
1867
            for (j = 0; j < c1->stream->nb_streams; j++) {
1868
                if (!c1->stream->feed)
1869
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1870
                else if (c1->feed_streams[j] >= 0)
1871
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1872
            }
1873
        }
1874

    
1875
        i++;
1876
        p = inet_ntoa(c1->from_addr.sin_addr);
1877
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1878
                    i,
1879
                    c1->stream ? c1->stream->filename : "",
1880
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1881
                    p,
1882
                    c1->protocol,
1883
                    http_state[c1->state]);
1884
        fmt_bytecount(pb, bitrate);
1885
        url_fprintf(pb, "<td align=right>");
1886
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1887
        url_fprintf(pb, "<td align=right>");
1888
        fmt_bytecount(pb, c1->data_count);
1889
        url_fprintf(pb, "\n");
1890
        c1 = c1->next;
1891
    }
1892
    url_fprintf(pb, "</TABLE>\n");
1893

    
1894
    /* date */
1895
    ti = time(NULL);
1896
    p = ctime(&ti);
1897
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1898
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1899

    
1900
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1901
    c->buffer_ptr = c->pb_buffer;
1902
    c->buffer_end = c->pb_buffer + len;
1903
}
1904

    
1905
/* check if the parser needs to be opened for stream i */
1906
static void open_parser(AVFormatContext *s, int i)
1907
{
1908
    AVStream *st = s->streams[i];
1909
    AVCodec *codec;
1910

    
1911
    if (!st->codec->codec) {
1912
        codec = avcodec_find_decoder(st->codec->codec_id);
1913
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1914
            st->codec->parse_only = 1;
1915
            if (avcodec_open(st->codec, codec) < 0)
1916
                st->codec->parse_only = 0;
1917
        }
1918
    }
1919
}
1920

    
1921
static int open_input_stream(HTTPContext *c, const char *info)
1922
{
1923
    char buf[128];
1924
    char input_filename[1024];
1925
    AVFormatContext *s;
1926
    int buf_size, i, ret;
1927
    int64_t stream_pos;
1928

    
1929
    /* find file name */
1930
    if (c->stream->feed) {
1931
        strcpy(input_filename, c->stream->feed->feed_filename);
1932
        buf_size = FFM_PACKET_SIZE;
1933
        /* compute position (absolute time) */
1934
        if (find_info_tag(buf, sizeof(buf), "date", info))
1935
        {
1936
            stream_pos = parse_date(buf, 0);
1937
            if (stream_pos == INT64_MIN)
1938
                return -1;
1939
        }
1940
        else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1941
            int prebuffer = strtol(buf, 0, 10);
1942
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1943
        } else
1944
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1945
    } else {
1946
        strcpy(input_filename, c->stream->feed_filename);
1947
        buf_size = 0;
1948
        /* compute position (relative time) */
1949
        if (find_info_tag(buf, sizeof(buf), "date", info))
1950
        {
1951
            stream_pos = parse_date(buf, 1);
1952
            if (stream_pos == INT64_MIN)
1953
                return -1;
1954
        }
1955
        else
1956
            stream_pos = 0;
1957
    }
1958
    if (input_filename[0] == '\0')
1959
        return -1;
1960

    
1961
#if 0
1962
    { time_t when = stream_pos / 1000000;
1963
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1964
    }
1965
#endif
1966

    
1967
    /* open stream */
1968
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1969
                                  buf_size, c->stream->ap_in)) < 0) {
1970
        http_log("could not open %s: %d\n", input_filename, ret);
1971
        return -1;
1972
    }
1973
    s->flags |= AVFMT_FLAG_GENPTS;
1974
    c->fmt_in = s;
1975
    av_find_stream_info(c->fmt_in);
1976

    
1977
    /* open each parser */
1978
    for(i=0;i<s->nb_streams;i++)
1979
        open_parser(s, i);
1980

    
1981
    /* choose stream as clock source (we favorize video stream if
1982
       present) for packet sending */
1983
    c->pts_stream_index = 0;
1984
    for(i=0;i<c->stream->nb_streams;i++) {
1985
        if (c->pts_stream_index == 0 &&
1986
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1987
            c->pts_stream_index = i;
1988
        }
1989
    }
1990

    
1991
#if 1
1992
    if (c->fmt_in->iformat->read_seek)
1993
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1994
#endif
1995
    /* set the start time (needed for maxtime and RTP packet timing) */
1996
    c->start_time = cur_time;
1997
    c->first_pts = AV_NOPTS_VALUE;
1998
    return 0;
1999
}
2000

    
2001
/* return the server clock (in us) */
2002
static int64_t get_server_clock(HTTPContext *c)
2003
{
2004
    /* compute current pts value from system time */
2005
    return (cur_time - c->start_time) * 1000;
2006
}
2007

    
2008
/* return the estimated time at which the current packet must be sent
2009
   (in us) */
2010
static int64_t get_packet_send_clock(HTTPContext *c)
2011
{
2012
    int bytes_left, bytes_sent, frame_bytes;
2013

    
2014
    frame_bytes = c->cur_frame_bytes;
2015
    if (frame_bytes <= 0)
2016
        return c->cur_pts;
2017
    else {
2018
        bytes_left = c->buffer_end - c->buffer_ptr;
2019
        bytes_sent = frame_bytes - bytes_left;
2020
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2021
    }
2022
}
2023

    
2024

    
2025
static int http_prepare_data(HTTPContext *c)
2026
{
2027
    int i, len, ret;
2028
    AVFormatContext *ctx;
2029

    
2030
    av_freep(&c->pb_buffer);
2031
    switch(c->state) {
2032
    case HTTPSTATE_SEND_DATA_HEADER:
2033
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2034
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
2035
                   sizeof(c->fmt_ctx.author));
2036
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2037
                   sizeof(c->fmt_ctx.comment));
2038
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2039
                   sizeof(c->fmt_ctx.copyright));
2040
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2041
                   sizeof(c->fmt_ctx.title));
2042

    
2043
        /* open output stream by using specified codecs */
2044
        c->fmt_ctx.oformat = c->stream->fmt;
2045
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2046
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2047
            AVStream *st;
2048
            AVStream *src;
2049
            st = av_mallocz(sizeof(AVStream));
2050
            c->fmt_ctx.streams[i] = st;
2051
            /* if file or feed, then just take streams from FFStream struct */
2052
            if (!c->stream->feed ||
2053
                c->stream->feed == c->stream)
2054
                src = c->stream->streams[i];
2055
            else
2056
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2057

    
2058
            *st = *src;
2059
            st->priv_data = 0;
2060
            st->codec->frame_number = 0; /* XXX: should be done in
2061
                                           AVStream, not in codec */
2062
        }
2063
        c->got_key_frame = 0;
2064

    
2065
        /* prepare header and save header data in a stream */
2066
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2067
            /* XXX: potential leak */
2068
            return -1;
2069
        }
2070
        c->fmt_ctx.pb->is_streamed = 1;
2071

    
2072
        /*
2073
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2074
         * Default value from FFmpeg
2075
         * Try to set it use configuration option
2076
         */
2077
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2078
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2079

    
2080
        av_set_parameters(&c->fmt_ctx, NULL);
2081
        if (av_write_header(&c->fmt_ctx) < 0) {
2082
            http_log("Error writing output header\n");
2083
            return -1;
2084
        }
2085

    
2086
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2087
        c->buffer_ptr = c->pb_buffer;
2088
        c->buffer_end = c->pb_buffer + len;
2089

    
2090
        c->state = HTTPSTATE_SEND_DATA;
2091
        c->last_packet_sent = 0;
2092
        break;
2093
    case HTTPSTATE_SEND_DATA:
2094
        /* find a new packet */
2095
        /* read a packet from the input stream */
2096
        if (c->stream->feed)
2097
            ffm_set_write_index(c->fmt_in,
2098
                                c->stream->feed->feed_write_index,
2099
                                c->stream->feed->feed_size);
2100

    
2101
        if (c->stream->max_time &&
2102
            c->stream->max_time + c->start_time - cur_time < 0)
2103
            /* We have timed out */
2104
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2105
        else {
2106
            AVPacket pkt;
2107
        redo:
2108
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2109
                if (c->stream->feed && c->stream->feed->feed_opened) {
2110
                    /* if coming from feed, it means we reached the end of the
2111
                       ffm file, so must wait for more data */
2112
                    c->state = HTTPSTATE_WAIT_FEED;
2113
                    return 1; /* state changed */
2114
                } else {
2115
                    if (c->stream->loop) {
2116
                        av_close_input_file(c->fmt_in);
2117
                        c->fmt_in = NULL;
2118
                        if (open_input_stream(c, "") < 0)
2119
                            goto no_loop;
2120
                        goto redo;
2121
                    } else {
2122
                    no_loop:
2123
                        /* must send trailer now because eof or error */
2124
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2125
                    }
2126
                }
2127
            } else {
2128
                int source_index = pkt.stream_index;
2129
                /* update first pts if needed */
2130
                if (c->first_pts == AV_NOPTS_VALUE) {
2131
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2132
                    c->start_time = cur_time;
2133
                }
2134
                /* send it to the appropriate stream */
2135
                if (c->stream->feed) {
2136
                    /* if coming from a feed, select the right stream */
2137
                    if (c->switch_pending) {
2138
                        c->switch_pending = 0;
2139
                        for(i=0;i<c->stream->nb_streams;i++) {
2140
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2141
                                if (pkt.flags & PKT_FLAG_KEY)
2142
                                    do_switch_stream(c, i);
2143
                            if (c->switch_feed_streams[i] >= 0)
2144
                                c->switch_pending = 1;
2145
                        }
2146
                    }
2147
                    for(i=0;i<c->stream->nb_streams;i++) {
2148
                        if (c->feed_streams[i] == pkt.stream_index) {
2149
                            AVStream *st = c->fmt_in->streams[source_index];
2150
                            pkt.stream_index = i;
2151
                            if (pkt.flags & PKT_FLAG_KEY &&
2152
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2153
                                 c->stream->nb_streams == 1))
2154
                                c->got_key_frame = 1;
2155
                            if (!c->stream->send_on_key || c->got_key_frame)
2156
                                goto send_it;
2157
                        }
2158
                    }
2159
                } else {
2160
                    AVCodecContext *codec;
2161

    
2162
                send_it:
2163
                    /* specific handling for RTP: we use several
2164
                       output stream (one for each RTP
2165
                       connection). XXX: need more abstract handling */
2166
                    if (c->is_packetized) {
2167
                        AVStream *st;
2168
                        /* compute send time and duration */
2169
                        st = c->fmt_in->streams[pkt.stream_index];
2170
                        c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2171
                        if (st->start_time != AV_NOPTS_VALUE)
2172
                            c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2173
                        c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2174
#if 0
2175
                        printf("index=%d pts=%0.3f duration=%0.6f\n",
2176
                               pkt.stream_index,
2177
                               (double)c->cur_pts /
2178
                               AV_TIME_BASE,
2179
                               (double)c->cur_frame_duration /
2180
                               AV_TIME_BASE);
2181
#endif
2182
                        /* find RTP context */
2183
                        c->packet_stream_index = pkt.stream_index;
2184
                        ctx = c->rtp_ctx[c->packet_stream_index];
2185
                        if(!ctx) {
2186
                            av_free_packet(&pkt);
2187
                            break;
2188
                        }
2189
                        codec = ctx->streams[0]->codec;
2190
                        /* only one stream per RTP connection */
2191
                        pkt.stream_index = 0;
2192
                    } else {
2193
                        ctx = &c->fmt_ctx;
2194
                        /* Fudge here */
2195
                        codec = ctx->streams[pkt.stream_index]->codec;
2196
                    }
2197

    
2198
                    if (c->is_packetized) {
2199
                        int max_packet_size;
2200
                        if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2201
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2202
                        else
2203
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2204
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2205
                    } else {
2206
                        ret = url_open_dyn_buf(&ctx->pb);
2207
                    }
2208
                    if (ret < 0) {
2209
                        /* XXX: potential leak */
2210
                        return -1;
2211
                    }
2212
                    c->fmt_ctx.pb->is_streamed = 1;
2213
                    if (pkt.dts != AV_NOPTS_VALUE)
2214
                        pkt.dts = av_rescale_q(pkt.dts,
2215
                                               c->fmt_in->streams[source_index]->time_base,
2216
                                               ctx->streams[pkt.stream_index]->time_base);
2217
                    if (pkt.pts != AV_NOPTS_VALUE)
2218
                        pkt.pts = av_rescale_q(pkt.pts,
2219
                                               c->fmt_in->streams[source_index]->time_base,
2220
                                               ctx->streams[pkt.stream_index]->time_base);
2221
                    pkt.duration = av_rescale_q(pkt.duration,
2222
                                                c->fmt_in->streams[source_index]->time_base,
2223
                                                ctx->streams[pkt.stream_index]->time_base);
2224
                    if (av_write_frame(ctx, &pkt) < 0) {
2225
                        http_log("Error writing frame to output\n");
2226
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2227
                    }
2228

    
2229
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2230
                    c->cur_frame_bytes = len;
2231
                    c->buffer_ptr = c->pb_buffer;
2232
                    c->buffer_end = c->pb_buffer + len;
2233

    
2234
                    codec->frame_number++;
2235
                    if (len == 0) {
2236
                        av_free_packet(&pkt);
2237
                        goto redo;
2238
                    }
2239
                }
2240
                av_free_packet(&pkt);
2241
            }
2242
        }
2243
        break;
2244
    default:
2245
    case HTTPSTATE_SEND_DATA_TRAILER:
2246
        /* last packet test ? */
2247
        if (c->last_packet_sent || c->is_packetized)
2248
            return -1;
2249
        ctx = &c->fmt_ctx;
2250
        /* prepare header */
2251
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2252
            /* XXX: potential leak */
2253
            return -1;
2254
        }
2255
        c->fmt_ctx.pb->is_streamed = 1;
2256
        av_write_trailer(ctx);
2257
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2258
        c->buffer_ptr = c->pb_buffer;
2259
        c->buffer_end = c->pb_buffer + len;
2260

    
2261
        c->last_packet_sent = 1;
2262
        break;
2263
    }
2264
    return 0;
2265
}
2266

    
2267
/* should convert the format at the same time */
2268
/* send data starting at c->buffer_ptr to the output connection
2269
   (either UDP or TCP connection) */
2270
static int http_send_data(HTTPContext *c)
2271
{
2272
    int len, ret;
2273

    
2274
    for(;;) {
2275
        if (c->buffer_ptr >= c->buffer_end) {
2276
            ret = http_prepare_data(c);
2277
            if (ret < 0)
2278
                return -1;
2279
            else if (ret != 0)
2280
                /* state change requested */
2281
                break;
2282
        } else {
2283
            if (c->is_packetized) {
2284
                /* RTP data output */
2285
                len = c->buffer_end - c->buffer_ptr;
2286
                if (len < 4) {
2287
                    /* fail safe - should never happen */
2288
                fail1:
2289
                    c->buffer_ptr = c->buffer_end;
2290
                    return 0;
2291
                }
2292
                len = (c->buffer_ptr[0] << 24) |
2293
                    (c->buffer_ptr[1] << 16) |
2294
                    (c->buffer_ptr[2] << 8) |
2295
                    (c->buffer_ptr[3]);
2296
                if (len > (c->buffer_end - c->buffer_ptr))
2297
                    goto fail1;
2298
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2299
                    /* nothing to send yet: we can wait */
2300
                    return 0;
2301
                }
2302

    
2303
                c->data_count += len;
2304
                update_datarate(&c->datarate, c->data_count);
2305
                if (c->stream)
2306
                    c->stream->bytes_served += len;
2307

    
2308
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2309
                    /* RTP packets are sent inside the RTSP TCP connection */
2310
                    ByteIOContext *pb;
2311
                    int interleaved_index, size;
2312
                    uint8_t header[4];
2313
                    HTTPContext *rtsp_c;
2314

    
2315
                    rtsp_c = c->rtsp_c;
2316
                    /* if no RTSP connection left, error */
2317
                    if (!rtsp_c)
2318
                        return -1;
2319
                    /* if already sending something, then wait. */
2320
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2321
                        break;
2322
                    if (url_open_dyn_buf(&pb) < 0)
2323
                        goto fail1;
2324
                    interleaved_index = c->packet_stream_index * 2;
2325
                    /* RTCP packets are sent at odd indexes */
2326
                    if (c->buffer_ptr[1] == 200)
2327
                        interleaved_index++;
2328
                    /* write RTSP TCP header */
2329
                    header[0] = '$';
2330
                    header[1] = interleaved_index;
2331
                    header[2] = len >> 8;
2332
                    header[3] = len;
2333
                    put_buffer(pb, header, 4);
2334
                    /* write RTP packet data */
2335
                    c->buffer_ptr += 4;
2336
                    put_buffer(pb, c->buffer_ptr, len);
2337
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2338
                    /* prepare asynchronous TCP sending */
2339
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2340
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2341
                    c->buffer_ptr += len;
2342

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

    
2378
                c->data_count += len;
2379
                update_datarate(&c->datarate, c->data_count);
2380
                if (c->stream)
2381
                    c->stream->bytes_served += len;
2382
                break;
2383
            }
2384
        }
2385
    } /* for(;;) */
2386
    return 0;
2387
}
2388

    
2389
static int http_start_receive_data(HTTPContext *c)
2390
{
2391
    int fd;
2392

    
2393
    if (c->stream->feed_opened)
2394
        return -1;
2395

    
2396
    /* Don't permit writing to this one */
2397
    if (c->stream->readonly)
2398
        return -1;
2399

    
2400
    /* open feed */
2401
    fd = open(c->stream->feed_filename, O_RDWR);
2402
    if (fd < 0) {
2403
        http_log("Error opening feeder file: %s\n", strerror(errno));
2404
        return -1;
2405
    }
2406
    c->feed_fd = fd;
2407

    
2408
    c->stream->feed_write_index = ffm_read_write_index(fd);
2409
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2410
    lseek(fd, 0, SEEK_SET);
2411

    
2412
    /* init buffer input */
2413
    c->buffer_ptr = c->buffer;
2414
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2415
    c->stream->feed_opened = 1;
2416
    return 0;
2417
}
2418

    
2419
static int http_receive_data(HTTPContext *c)
2420
{
2421
    HTTPContext *c1;
2422

    
2423
    if (c->buffer_end > c->buffer_ptr) {
2424
        int len;
2425

    
2426
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2427
        if (len < 0) {
2428
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2429
                ff_neterrno() != FF_NETERROR(EINTR))
2430
                /* error : close connection */
2431
                goto fail;
2432
        } else if (len == 0)
2433
            /* end of connection : close it */
2434
            goto fail;
2435
        else {
2436
            c->buffer_ptr += len;
2437
            c->data_count += len;
2438
            update_datarate(&c->datarate, c->data_count);
2439
        }
2440
    }
2441

    
2442
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2443
        if (c->buffer[0] != 'f' ||
2444
            c->buffer[1] != 'm') {
2445
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2446
            goto fail;
2447
        }
2448
    }
2449

    
2450
    if (c->buffer_ptr >= c->buffer_end) {
2451
        FFStream *feed = c->stream;
2452
        /* a packet has been received : write it in the store, except
2453
           if header */
2454
        if (c->data_count > FFM_PACKET_SIZE) {
2455

    
2456
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2457
            /* XXX: use llseek or url_seek */
2458
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2459
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2460
                http_log("Error writing to feed file: %s\n", strerror(errno));
2461
                goto fail;
2462
            }
2463

    
2464
            feed->feed_write_index += FFM_PACKET_SIZE;
2465
            /* update file size */
2466
            if (feed->feed_write_index > c->stream->feed_size)
2467
                feed->feed_size = feed->feed_write_index;
2468

    
2469
            /* handle wrap around if max file size reached */
2470
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2471
                feed->feed_write_index = FFM_PACKET_SIZE;
2472

    
2473
            /* write index */
2474
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2475

    
2476
            /* wake up any waiting connections */
2477
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2478
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2479
                    c1->stream->feed == c->stream->feed)
2480
                    c1->state = HTTPSTATE_SEND_DATA;
2481
            }
2482
        } else {
2483
            /* We have a header in our hands that contains useful data */
2484
            AVFormatContext *s = NULL;
2485
            ByteIOContext *pb;
2486
            AVInputFormat *fmt_in;
2487
            int i;
2488

    
2489
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2490
            pb->is_streamed = 1;
2491

    
2492
            /* use feed output format name to find corresponding input format */
2493
            fmt_in = av_find_input_format(feed->fmt->name);
2494
            if (!fmt_in)
2495
                goto fail;
2496

    
2497
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2498
                av_free(pb);
2499
                goto fail;
2500
            }
2501

    
2502
            /* Now we have the actual streams */
2503
            if (s->nb_streams != feed->nb_streams) {
2504
                av_close_input_stream(s);
2505
                av_free(pb);
2506
                goto fail;
2507
            }
2508

    
2509
            for (i = 0; i < s->nb_streams; i++)
2510
                memcpy(feed->streams[i]->codec,
2511
                       s->streams[i]->codec, sizeof(AVCodecContext));
2512

    
2513
            av_close_input_stream(s);
2514
            av_free(pb);
2515
        }
2516
        c->buffer_ptr = c->buffer;
2517
    }
2518

    
2519
    return 0;
2520
 fail:
2521
    c->stream->feed_opened = 0;
2522
    close(c->feed_fd);
2523
    /* wake up any waiting connections to stop waiting for feed */
2524
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2525
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2526
            c1->stream->feed == c->stream->feed)
2527
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2528
    }
2529
    return -1;
2530
}
2531

    
2532
/********************************************************************/
2533
/* RTSP handling */
2534

    
2535
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2536
{
2537
    const char *str;
2538
    time_t ti;
2539
    char *p;
2540
    char buf2[32];
2541

    
2542
    switch(error_number) {
2543
    case RTSP_STATUS_OK:
2544
        str = "OK";
2545
        break;
2546
    case RTSP_STATUS_METHOD:
2547
        str = "Method Not Allowed";
2548
        break;
2549
    case RTSP_STATUS_BANDWIDTH:
2550
        str = "Not Enough Bandwidth";
2551
        break;
2552
    case RTSP_STATUS_SESSION:
2553
        str = "Session Not Found";
2554
        break;
2555
    case RTSP_STATUS_STATE:
2556
        str = "Method Not Valid in This State";
2557
        break;
2558
    case RTSP_STATUS_AGGREGATE:
2559
        str = "Aggregate operation not allowed";
2560
        break;
2561
    case RTSP_STATUS_ONLY_AGGREGATE:
2562
        str = "Only aggregate operation allowed";
2563
        break;
2564
    case RTSP_STATUS_TRANSPORT:
2565
        str = "Unsupported transport";
2566
        break;
2567
    case RTSP_STATUS_INTERNAL:
2568
        str = "Internal Server Error";
2569
        break;
2570
    case RTSP_STATUS_SERVICE:
2571
        str = "Service Unavailable";
2572
        break;
2573
    case RTSP_STATUS_VERSION:
2574
        str = "RTSP Version not supported";
2575
        break;
2576
    default:
2577
        str = "Unknown Error";
2578
        break;
2579
    }
2580

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

    
2584
    /* output GMT time */
2585
    ti = time(NULL);
2586
    p = ctime(&ti);
2587
    strcpy(buf2, p);
2588
    p = buf2 + strlen(p) - 1;
2589
    if (*p == '\n')
2590
        *p = '\0';
2591
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2592
}
2593

    
2594
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2595
{
2596
    rtsp_reply_header(c, error_number);
2597
    url_fprintf(c->pb, "\r\n");
2598
}
2599

    
2600
static int rtsp_parse_request(HTTPContext *c)
2601
{
2602
    const char *p, *p1, *p2;
2603
    char cmd[32];
2604
    char url[1024];
2605
    char protocol[32];
2606
    char line[1024];
2607
    int len;
2608
    RTSPHeader header1, *header = &header1;
2609

    
2610
    c->buffer_ptr[0] = '\0';
2611
    p = c->buffer;
2612

    
2613
    get_word(cmd, sizeof(cmd), &p);
2614
    get_word(url, sizeof(url), &p);
2615
    get_word(protocol, sizeof(protocol), &p);
2616

    
2617
    av_strlcpy(c->method, cmd, sizeof(c->method));
2618
    av_strlcpy(c->url, url, sizeof(c->url));
2619
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2620

    
2621
    if (url_open_dyn_buf(&c->pb) < 0) {
2622
        /* XXX: cannot do more */
2623
        c->pb = NULL; /* safety */
2624
        return -1;
2625
    }
2626

    
2627
    /* check version name */
2628
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2629
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2630
        goto the_end;
2631
    }
2632

    
2633
    /* parse each header line */
2634
    memset(header, 0, sizeof(RTSPHeader));
2635
    /* skip to next line */
2636
    while (*p != '\n' && *p != '\0')
2637
        p++;
2638
    if (*p == '\n')
2639
        p++;
2640
    while (*p != '\0') {
2641
        p1 = strchr(p, '\n');
2642
        if (!p1)
2643
            break;
2644
        p2 = p1;
2645
        if (p2 > p && p2[-1] == '\r')
2646
            p2--;
2647
        /* skip empty line */
2648
        if (p2 == p)
2649
            break;
2650
        len = p2 - p;
2651
        if (len > sizeof(line) - 1)
2652
            len = sizeof(line) - 1;
2653
        memcpy(line, p, len);
2654
        line[len] = '\0';
2655
        rtsp_parse_line(header, line);
2656
        p = p1 + 1;
2657
    }
2658

    
2659
    /* handle sequence number */
2660
    c->seq = header->seq;
2661

    
2662
    if (!strcmp(cmd, "DESCRIBE"))
2663
        rtsp_cmd_describe(c, url);
2664
    else if (!strcmp(cmd, "OPTIONS"))
2665
        rtsp_cmd_options(c, url);
2666
    else if (!strcmp(cmd, "SETUP"))
2667
        rtsp_cmd_setup(c, url, header);
2668
    else if (!strcmp(cmd, "PLAY"))
2669
        rtsp_cmd_play(c, url, header);
2670
    else if (!strcmp(cmd, "PAUSE"))
2671
        rtsp_cmd_pause(c, url, header);
2672
    else if (!strcmp(cmd, "TEARDOWN"))
2673
        rtsp_cmd_teardown(c, url, header);
2674
    else
2675
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2676

    
2677
 the_end:
2678
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2679
    c->pb = NULL; /* safety */
2680
    if (len < 0) {
2681
        /* XXX: cannot do more */
2682
        return -1;
2683
    }
2684
    c->buffer_ptr = c->pb_buffer;
2685
    c->buffer_end = c->pb_buffer + len;
2686
    c->state = RTSPSTATE_SEND_REPLY;
2687
    return 0;
2688
}
2689

    
2690
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2691
                                   struct in_addr my_ip)
2692
{
2693
    AVFormatContext *avc;
2694
    AVStream avs[MAX_STREAMS];
2695
    int i;
2696

    
2697
    avc =  av_alloc_format_context();
2698
    if (avc == NULL) {
2699
        return -1;
2700
    }
2701
    if (stream->title[0] != 0) {
2702
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2703
    } else {
2704
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2705
    }
2706
    avc->nb_streams = stream->nb_streams;
2707
    if (stream->is_multicast) {
2708
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2709
                 inet_ntoa(stream->multicast_ip),
2710
                 stream->multicast_port, stream->multicast_ttl);
2711
    }
2712

    
2713
    for(i = 0; i < stream->nb_streams; i++) {
2714
        avc->streams[i] = &avs[i];
2715
        avc->streams[i]->codec = stream->streams[i]->codec;
2716
    }
2717
    *pbuffer = av_mallocz(2048);
2718
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2719
    av_free(avc);
2720

    
2721
    return strlen(*pbuffer);
2722
}
2723

    
2724
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2725
{
2726
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2727
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2728
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2729
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2730
    url_fprintf(c->pb, "\r\n");
2731
}
2732

    
2733
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2734
{
2735
    FFStream *stream;
2736
    char path1[1024];
2737
    const char *path;
2738
    uint8_t *content;
2739
    int content_length, len;
2740
    struct sockaddr_in my_addr;
2741

    
2742
    /* find which url is asked */
2743
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2744
    path = path1;
2745
    if (*path == '/')
2746
        path++;
2747

    
2748
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2749
        if (!stream->is_feed &&
2750
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2751
            !strcmp(path, stream->filename)) {
2752
            goto found;
2753
        }
2754
    }
2755
    /* no stream found */
2756
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2757
    return;
2758

    
2759
 found:
2760
    /* prepare the media description in sdp format */
2761

    
2762
    /* get the host IP */
2763
    len = sizeof(my_addr);
2764
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2765
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2766
    if (content_length < 0) {
2767
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2768
        return;
2769
    }
2770
    rtsp_reply_header(c, RTSP_STATUS_OK);
2771
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2772
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2773
    url_fprintf(c->pb, "\r\n");
2774
    put_buffer(c->pb, content, content_length);
2775
}
2776

    
2777
static HTTPContext *find_rtp_session(const char *session_id)
2778
{
2779
    HTTPContext *c;
2780

    
2781
    if (session_id[0] == '\0')
2782
        return NULL;
2783

    
2784
    for(c = first_http_ctx; c != NULL; c = c->next) {
2785
        if (!strcmp(c->session_id, session_id))
2786
            return c;
2787
    }
2788
    return NULL;
2789
}
2790

    
2791
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2792
{
2793
    RTSPTransportField *th;
2794
    int i;
2795

    
2796
    for(i=0;i<h->nb_transports;i++) {
2797
        th = &h->transports[i];
2798
        if (th->protocol == protocol)
2799
            return th;
2800
    }
2801
    return NULL;
2802
}
2803

    
2804
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2805
                           RTSPHeader *h)
2806
{
2807
    FFStream *stream;
2808
    int stream_index, port;
2809
    char buf[1024];
2810
    char path1[1024];
2811
    const char *path;
2812
    HTTPContext *rtp_c;
2813
    RTSPTransportField *th;
2814
    struct sockaddr_in dest_addr;
2815
    RTSPActionServerSetup setup;
2816

    
2817
    /* find which url is asked */
2818
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2819
    path = path1;
2820
    if (*path == '/')
2821
        path++;
2822

    
2823
    /* now check each stream */
2824
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2825
        if (!stream->is_feed &&
2826
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2827
            /* accept aggregate filenames only if single stream */
2828
            if (!strcmp(path, stream->filename)) {
2829
                if (stream->nb_streams != 1) {
2830
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2831
                    return;
2832
                }
2833
                stream_index = 0;
2834
                goto found;
2835
            }
2836

    
2837
            for(stream_index = 0; stream_index < stream->nb_streams;
2838
                stream_index++) {
2839
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2840
                         stream->filename, stream_index);
2841
                if (!strcmp(path, buf))
2842
                    goto found;
2843
            }
2844
        }
2845
    }
2846
    /* no stream found */
2847
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2848
    return;
2849
 found:
2850

    
2851
    /* generate session id if needed */
2852
    if (h->session_id[0] == '\0')
2853
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2854
                 av_random(&random_state), av_random(&random_state));
2855

    
2856
    /* find rtp session, and create it if none found */
2857
    rtp_c = find_rtp_session(h->session_id);
2858
    if (!rtp_c) {
2859
        /* always prefer UDP */
2860
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2861
        if (!th) {
2862
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2863
            if (!th) {
2864
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2865
                return;
2866
            }
2867
        }
2868

    
2869
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2870
                                   th->protocol);
2871
        if (!rtp_c) {
2872
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2873
            return;
2874
        }
2875

    
2876
        /* open input stream */
2877
        if (open_input_stream(rtp_c, "") < 0) {
2878
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2879
            return;
2880
        }
2881
    }
2882

    
2883
    /* test if stream is OK (test needed because several SETUP needs
2884
       to be done for a given file) */
2885
    if (rtp_c->stream != stream) {
2886
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2887
        return;
2888
    }
2889

    
2890
    /* test if stream is already set up */
2891
    if (rtp_c->rtp_ctx[stream_index]) {
2892
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2893
        return;
2894
    }
2895

    
2896
    /* check transport */
2897
    th = find_transport(h, rtp_c->rtp_protocol);
2898
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2899
                th->client_port_min <= 0)) {
2900
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2901
        return;
2902
    }
2903

    
2904
    /* setup default options */
2905
    setup.transport_option[0] = '\0';
2906
    dest_addr = rtp_c->from_addr;
2907
    dest_addr.sin_port = htons(th->client_port_min);
2908

    
2909
    /* setup stream */
2910
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2911
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2912
        return;
2913
    }
2914

    
2915
    /* now everything is OK, so we can send the connection parameters */
2916
    rtsp_reply_header(c, RTSP_STATUS_OK);
2917
    /* session ID */
2918
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2919

    
2920
    switch(rtp_c->rtp_protocol) {
2921
    case RTSP_PROTOCOL_RTP_UDP:
2922
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2923
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2924
                    "client_port=%d-%d;server_port=%d-%d",
2925
                    th->client_port_min, th->client_port_min + 1,
2926
                    port, port + 1);
2927
        break;
2928
    case RTSP_PROTOCOL_RTP_TCP:
2929
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2930
                    stream_index * 2, stream_index * 2 + 1);
2931
        break;
2932
    default:
2933
        break;
2934
    }
2935
    if (setup.transport_option[0] != '\0')
2936
        url_fprintf(c->pb, ";%s", setup.transport_option);
2937
    url_fprintf(c->pb, "\r\n");
2938

    
2939

    
2940
    url_fprintf(c->pb, "\r\n");
2941
}
2942

    
2943

    
2944
/* find an rtp connection by using the session ID. Check consistency
2945
   with filename */
2946
static HTTPContext *find_rtp_session_with_url(const char *url,
2947
                                              const char *session_id)
2948
{
2949
    HTTPContext *rtp_c;
2950
    char path1[1024];
2951
    const char *path;
2952
    char buf[1024];
2953
    int s;
2954

    
2955
    rtp_c = find_rtp_session(session_id);
2956
    if (!rtp_c)
2957
        return NULL;
2958

    
2959
    /* find which url is asked */
2960
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2961
    path = path1;
2962
    if (*path == '/')
2963
        path++;
2964
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2965
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2966
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2967
        rtp_c->stream->filename, s);
2968
      if(!strncmp(path, buf, sizeof(buf))) {
2969
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2970
        return rtp_c;
2971
      }
2972
    }
2973
    return NULL;
2974
}
2975

    
2976
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2977
{
2978
    HTTPContext *rtp_c;
2979

    
2980
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2981
    if (!rtp_c) {
2982
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2983
        return;
2984
    }
2985

    
2986
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2987
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2988
        rtp_c->state != HTTPSTATE_READY) {
2989
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2990
        return;
2991
    }
2992

    
2993
#if 0
2994
    /* XXX: seek in stream */
2995
    if (h->range_start != AV_NOPTS_VALUE) {
2996
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2997
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2998
    }
2999
#endif
3000

    
3001
    rtp_c->state = HTTPSTATE_SEND_DATA;
3002

    
3003
    /* now everything is OK, so we can send the connection parameters */
3004
    rtsp_reply_header(c, RTSP_STATUS_OK);
3005
    /* session ID */
3006
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3007
    url_fprintf(c->pb, "\r\n");
3008
}
3009

    
3010
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3011
{
3012
    HTTPContext *rtp_c;
3013

    
3014
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3015
    if (!rtp_c) {
3016
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3017
        return;
3018
    }
3019

    
3020
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3021
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3022
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3023
        return;
3024
    }
3025

    
3026
    rtp_c->state = HTTPSTATE_READY;
3027
    rtp_c->first_pts = AV_NOPTS_VALUE;
3028
    /* now everything is OK, so we can send the connection parameters */
3029
    rtsp_reply_header(c, RTSP_STATUS_OK);
3030
    /* session ID */
3031
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3032
    url_fprintf(c->pb, "\r\n");
3033
}
3034

    
3035
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3036
{
3037
    HTTPContext *rtp_c;
3038
    char session_id[32];
3039

    
3040
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3041
    if (!rtp_c) {
3042
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3043
        return;
3044
    }
3045

    
3046
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3047

    
3048
    /* abort the session */
3049
    close_connection(rtp_c);
3050

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

    
3058

    
3059
/********************************************************************/
3060
/* RTP handling */
3061

    
3062
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3063
                                       FFStream *stream, const char *session_id,
3064
                                       enum RTSPProtocol rtp_protocol)
3065
{
3066
    HTTPContext *c = NULL;
3067
    const char *proto_str;
3068

    
3069
    /* XXX: should output a warning page when coming
3070
       close to the connection limit */
3071
    if (nb_connections >= nb_max_connections)
3072
        goto fail;
3073

    
3074
    /* add a new connection */
3075
    c = av_mallocz(sizeof(HTTPContext));
3076
    if (!c)
3077
        goto fail;
3078

    
3079
    c->fd = -1;
3080
    c->poll_entry = NULL;
3081
    c->from_addr = *from_addr;
3082
    c->buffer_size = IOBUFFER_INIT_SIZE;
3083
    c->buffer = av_malloc(c->buffer_size);
3084
    if (!c->buffer)
3085
        goto fail;
3086
    nb_connections++;
3087
    c->stream = stream;
3088
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3089
    c->state = HTTPSTATE_READY;
3090
    c->is_packetized = 1;
3091
    c->rtp_protocol = rtp_protocol;
3092

    
3093
    /* protocol is shown in statistics */
3094
    switch(c->rtp_protocol) {
3095
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3096
        proto_str = "MCAST";
3097
        break;
3098
    case RTSP_PROTOCOL_RTP_UDP:
3099
        proto_str = "UDP";
3100
        break;
3101
    case RTSP_PROTOCOL_RTP_TCP:
3102
        proto_str = "TCP";
3103
        break;
3104
    default:
3105
        proto_str = "???";
3106
        break;
3107
    }
3108
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3109
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3110

    
3111
    current_bandwidth += stream->bandwidth;
3112

    
3113
    c->next = first_http_ctx;
3114
    first_http_ctx = c;
3115
    return c;
3116

    
3117
 fail:
3118
    if (c) {
3119
        av_free(c->buffer);
3120
        av_free(c);
3121
    }
3122
    return NULL;
3123
}
3124

    
3125
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3126
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3127
   used. */
3128
static int rtp_new_av_stream(HTTPContext *c,
3129
                             int stream_index, struct sockaddr_in *dest_addr,
3130
                             HTTPContext *rtsp_c)
3131
{
3132
    AVFormatContext *ctx;
3133
    AVStream *st;
3134
    char *ipaddr;
3135
    URLContext *h = NULL;
3136
    uint8_t *dummy_buf;
3137
    char buf2[32];
3138
    int max_packet_size;
3139

    
3140
    /* now we can open the relevant output stream */
3141
    ctx = av_alloc_format_context();
3142
    if (!ctx)
3143
        return -1;
3144
    ctx->oformat = guess_format("rtp", NULL, NULL);
3145

    
3146
    st = av_mallocz(sizeof(AVStream));
3147
    if (!st)
3148
        goto fail;
3149
    st->codec= avcodec_alloc_context();
3150
    ctx->nb_streams = 1;
3151
    ctx->streams[0] = st;
3152

    
3153
    if (!c->stream->feed ||
3154
        c->stream->feed == c->stream)
3155
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3156
    else
3157
        memcpy(st,
3158
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3159
               sizeof(AVStream));
3160
    st->priv_data = NULL;
3161

    
3162
    /* build destination RTP address */
3163
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3164

    
3165
    switch(c->rtp_protocol) {
3166
    case RTSP_PROTOCOL_RTP_UDP:
3167
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3168
        /* RTP/UDP case */
3169

    
3170
        /* XXX: also pass as parameter to function ? */
3171
        if (c->stream->is_multicast) {
3172
            int ttl;
3173
            ttl = c->stream->multicast_ttl;
3174
            if (!ttl)
3175
                ttl = 16;
3176
            snprintf(ctx->filename, sizeof(ctx->filename),
3177
                     "rtp://%s:%d?multicast=1&ttl=%d",
3178
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3179
        } else {
3180
            snprintf(ctx->filename, sizeof(ctx->filename),
3181
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3182
        }
3183

    
3184
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3185
            goto fail;
3186
        c->rtp_handles[stream_index] = h;
3187
        max_packet_size = url_get_max_packet_size(h);
3188
        break;
3189
    case RTSP_PROTOCOL_RTP_TCP:
3190
        /* RTP/TCP case */
3191
        c->rtsp_c = rtsp_c;
3192
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3193
        break;
3194
    default:
3195
        goto fail;
3196
    }
3197

    
3198
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3199
             ipaddr, ntohs(dest_addr->sin_port),
3200
             ctime1(buf2),
3201
             c->stream->filename, stream_index, c->protocol);
3202

    
3203
    /* normally, no packets should be output here, but the packet size may be checked */
3204
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3205
        /* XXX: close stream */
3206
        goto fail;
3207
    }
3208
    av_set_parameters(ctx, NULL);
3209
    if (av_write_header(ctx) < 0) {
3210
    fail:
3211
        if (h)
3212
            url_close(h);
3213
        av_free(ctx);
3214
        return -1;
3215
    }
3216
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3217
    av_free(dummy_buf);
3218

    
3219
    c->rtp_ctx[stream_index] = ctx;
3220
    return 0;
3221
}
3222

    
3223
/********************************************************************/
3224
/* ffserver initialization */
3225

    
3226
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3227
{
3228
    AVStream *fst;
3229

    
3230
    fst = av_mallocz(sizeof(AVStream));
3231
    if (!fst)
3232
        return NULL;
3233
    fst->codec= avcodec_alloc_context();
3234
    fst->priv_data = av_mallocz(sizeof(FeedData));
3235
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3236
    fst->index = stream->nb_streams;
3237
    av_set_pts_info(fst, 33, 1, 90000);
3238
    stream->streams[stream->nb_streams++] = fst;
3239
    return fst;
3240
}
3241

    
3242
/* return the stream number in the feed */
3243
static int add_av_stream(FFStream *feed, AVStream *st)
3244
{
3245
    AVStream *fst;
3246
    AVCodecContext *av, *av1;
3247
    int i;
3248

    
3249
    av = st->codec;
3250
    for(i=0;i<feed->nb_streams;i++) {
3251
        st = feed->streams[i];
3252
        av1 = st->codec;
3253
        if (av1->codec_id == av->codec_id &&
3254
            av1->codec_type == av->codec_type &&
3255
            av1->bit_rate == av->bit_rate) {
3256

    
3257
            switch(av->codec_type) {
3258
            case CODEC_TYPE_AUDIO:
3259
                if (av1->channels == av->channels &&
3260
                    av1->sample_rate == av->sample_rate)
3261
                    goto found;
3262
                break;
3263
            case CODEC_TYPE_VIDEO:
3264
                if (av1->width == av->width &&
3265
                    av1->height == av->height &&
3266
                    av1->time_base.den == av->time_base.den &&
3267
                    av1->time_base.num == av->time_base.num &&
3268
                    av1->gop_size == av->gop_size)
3269
                    goto found;
3270
                break;
3271
            default:
3272
                abort();
3273
            }
3274
        }
3275
    }
3276

    
3277
    fst = add_av_stream1(feed, av);
3278
    if (!fst)
3279
        return -1;
3280
    return feed->nb_streams - 1;
3281
 found:
3282
    return i;
3283
}
3284

    
3285
static void remove_stream(FFStream *stream)
3286
{
3287
    FFStream **ps;
3288
    ps = &first_stream;
3289
    while (*ps != NULL) {
3290
        if (*ps == stream)
3291
            *ps = (*ps)->next;
3292
        else
3293
            ps = &(*ps)->next;
3294
    }
3295
}
3296

    
3297
/* specific mpeg4 handling : we extract the raw parameters */
3298
static void extract_mpeg4_header(AVFormatContext *infile)
3299
{
3300
    int mpeg4_count, i, size;
3301
    AVPacket pkt;
3302
    AVStream *st;
3303
    const uint8_t *p;
3304

    
3305
    mpeg4_count = 0;
3306
    for(i=0;i<infile->nb_streams;i++) {
3307
        st = infile->streams[i];
3308
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3309
            st->codec->extradata_size == 0) {
3310
            mpeg4_count++;
3311
        }
3312
    }
3313
    if (!mpeg4_count)
3314
        return;
3315

    
3316
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3317
    while (mpeg4_count > 0) {
3318
        if (av_read_packet(infile, &pkt) < 0)
3319
            break;
3320
        st = infile->streams[pkt.stream_index];
3321
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3322
            st->codec->extradata_size == 0) {
3323
            av_freep(&st->codec->extradata);
3324
            /* fill extradata with the header */
3325
            /* XXX: we make hard suppositions here ! */
3326
            p = pkt.data;
3327
            while (p < pkt.data + pkt.size - 4) {
3328
                /* stop when vop header is found */
3329
                if (p[0] == 0x00 && p[1] == 0x00 &&
3330
                    p[2] == 0x01 && p[3] == 0xb6) {
3331
                    size = p - pkt.data;
3332
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3333
                    st->codec->extradata = av_malloc(size);
3334
                    st->codec->extradata_size = size;
3335
                    memcpy(st->codec->extradata, pkt.data, size);
3336
                    break;
3337
                }
3338
                p++;
3339
            }
3340
            mpeg4_count--;
3341
        }
3342
        av_free_packet(&pkt);
3343
    }
3344
}
3345

    
3346
/* compute the needed AVStream for each file */
3347
static void build_file_streams(void)
3348
{
3349
    FFStream *stream, *stream_next;
3350
    AVFormatContext *infile;
3351
    int i, ret;
3352

    
3353
    /* gather all streams */
3354
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3355
        stream_next = stream->next;
3356
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3357
            !stream->feed) {
3358
            /* the stream comes from a file */
3359
            /* try to open the file */
3360
            /* open stream */
3361
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3362
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3363
                /* specific case : if transport stream output to RTP,
3364
                   we use a raw transport stream reader */
3365
                stream->ap_in->mpeg2ts_raw = 1;
3366
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3367
            }
3368

    
3369
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3370
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3371
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3372
                /* remove stream (no need to spend more time on it) */
3373
            fail:
3374
                remove_stream(stream);
3375
            } else {
3376
                /* find all the AVStreams inside and reference them in
3377
                   'stream' */
3378
                if (av_find_stream_info(infile) < 0) {
3379
                    http_log("Could not find codec parameters from '%s'\n",
3380
                             stream->feed_filename);
3381
                    av_close_input_file(infile);
3382
                    goto fail;
3383
                }
3384
                extract_mpeg4_header(infile);
3385

    
3386
                for(i=0;i<infile->nb_streams;i++)
3387
                    add_av_stream1(stream, infile->streams[i]->codec);
3388

    
3389
                av_close_input_file(infile);
3390
            }
3391
        }
3392
    }
3393
}
3394

    
3395
/* compute the needed AVStream for each feed */
3396
static void build_feed_streams(void)
3397
{
3398
    FFStream *stream, *feed;
3399
    int i;
3400

    
3401
    /* gather all streams */
3402
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3403
        feed = stream->feed;
3404
        if (feed) {
3405
            if (!stream->is_feed) {
3406
                /* we handle a stream coming from a feed */
3407
                for(i=0;i<stream->nb_streams;i++)
3408
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3409
            }
3410
        }
3411
    }
3412

    
3413
    /* gather all streams */
3414
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3415
        feed = stream->feed;
3416
        if (feed) {
3417
            if (stream->is_feed) {
3418
                for(i=0;i<stream->nb_streams;i++)
3419
                    stream->feed_streams[i] = i;
3420
            }
3421
        }
3422
    }
3423

    
3424
    /* create feed files if needed */
3425
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3426
        int fd;
3427

    
3428
        if (url_exist(feed->feed_filename)) {
3429
            /* See if it matches */
3430
            AVFormatContext *s;
3431
            int matches = 0;
3432

    
3433
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3434
                /* Now see if it matches */
3435
                if (s->nb_streams == feed->nb_streams) {
3436
                    matches = 1;
3437
                    for(i=0;i<s->nb_streams;i++) {
3438
                        AVStream *sf, *ss;
3439
                        sf = feed->streams[i];
3440
                        ss = s->streams[i];
3441

    
3442
                        if (sf->index != ss->index ||
3443
                            sf->id != ss->id) {
3444
                            printf("Index & Id do not match for stream %d (%s)\n",
3445
                                   i, feed->feed_filename);
3446
                            matches = 0;
3447
                        } else {
3448
                            AVCodecContext *ccf, *ccs;
3449

    
3450
                            ccf = sf->codec;
3451
                            ccs = ss->codec;
3452
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3453

    
3454
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3455
                                printf("Codecs do not match for stream %d\n", i);
3456
                                matches = 0;
3457
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3458
                                printf("Codec bitrates do not match for stream %d\n", i);
3459
                                matches = 0;
3460
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3461
                                if (CHECK_CODEC(time_base.den) ||
3462
                                    CHECK_CODEC(time_base.num) ||
3463
                                    CHECK_CODEC(width) ||
3464
                                    CHECK_CODEC(height)) {
3465
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3466
                                    matches = 0;
3467
                                }
3468
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3469
                                if (CHECK_CODEC(sample_rate) ||
3470
                                    CHECK_CODEC(channels) ||
3471
                                    CHECK_CODEC(frame_size)) {
3472
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3473
                                    matches = 0;
3474
                                }
3475
                            } else {
3476
                                printf("Unknown codec type\n");
3477
                                matches = 0;
3478
                            }
3479
                        }
3480
                        if (!matches)
3481
                            break;
3482
                    }
3483
                } else
3484
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3485
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3486

    
3487
                av_close_input_file(s);
3488
            } else
3489
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3490
                        feed->feed_filename);
3491

    
3492
            if (!matches) {
3493
                if (feed->readonly) {
3494
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3495
                        feed->feed_filename);
3496
                    exit(1);
3497
                }
3498
                unlink(feed->feed_filename);
3499
            }
3500
        }
3501
        if (!url_exist(feed->feed_filename)) {
3502
            AVFormatContext s1, *s = &s1;
3503

    
3504
            if (feed->readonly) {
3505
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3506
                    feed->feed_filename);
3507
                exit(1);
3508
            }
3509

    
3510
            /* only write the header of the ffm file */
3511
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3512
                http_log("Could not open output feed file '%s'\n",
3513
                         feed->feed_filename);
3514
                exit(1);
3515
            }
3516
            s->oformat = feed->fmt;
3517
            s->nb_streams = feed->nb_streams;
3518
            for(i=0;i<s->nb_streams;i++) {
3519
                AVStream *st;
3520
                st = feed->streams[i];
3521
                s->streams[i] = st;
3522
            }
3523
            av_set_parameters(s, NULL);
3524
            if (av_write_header(s) < 0) {
3525
                http_log("Container doesn't supports the required parameters\n");
3526
                exit(1);
3527
            }
3528
            /* XXX: need better api */
3529
            av_freep(&s->priv_data);
3530
            url_fclose(s->pb);
3531
        }
3532
        /* get feed size and write index */
3533
        fd = open(feed->feed_filename, O_RDONLY);
3534
        if (fd < 0) {
3535
            http_log("Could not open output feed file '%s'\n",
3536
                    feed->feed_filename);
3537
            exit(1);
3538
        }
3539

    
3540
        feed->feed_write_index = ffm_read_write_index(fd);
3541
        feed->feed_size = lseek(fd, 0, SEEK_END);
3542
        /* ensure that we do not wrap before the end of file */
3543
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3544
            feed->feed_max_size = feed->feed_size;
3545

    
3546
        close(fd);
3547
    }
3548
}
3549

    
3550
/* compute the bandwidth used by each stream */
3551
static void compute_bandwidth(void)
3552
{
3553
    unsigned bandwidth;
3554
    int i;
3555
    FFStream *stream;
3556

    
3557
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3558
        bandwidth = 0;
3559
        for(i=0;i<stream->nb_streams;i++) {
3560
            AVStream *st = stream->streams[i];
3561
            switch(st->codec->codec_type) {
3562
            case CODEC_TYPE_AUDIO:
3563
            case CODEC_TYPE_VIDEO:
3564
                bandwidth += st->codec->bit_rate;
3565
                break;
3566
            default:
3567
                break;
3568
            }
3569
        }
3570
        stream->bandwidth = (bandwidth + 999) / 1000;
3571
    }
3572
}
3573

    
3574
static void get_arg(char *buf, int buf_size, const char **pp)
3575
{
3576
    const char *p;
3577
    char *q;
3578
    int quote;
3579

    
3580
    p = *pp;
3581
    while (isspace(*p)) p++;
3582
    q = buf;
3583
    quote = 0;
3584
    if (*p == '\"' || *p == '\'')
3585
        quote = *p++;
3586
    for(;;) {
3587
        if (quote) {
3588
            if (*p == quote)
3589
                break;
3590
        } else {
3591
            if (isspace(*p))
3592
                break;
3593
        }
3594
        if (*p == '\0')
3595
            break;
3596
        if ((q - buf) < buf_size - 1)
3597
            *q++ = *p;
3598
        p++;
3599
    }
3600
    *q = '\0';
3601
    if (quote && *p == quote)
3602
        p++;
3603
    *pp = p;
3604
}
3605

    
3606
/* add a codec and set the default parameters */
3607
static void add_codec(FFStream *stream, AVCodecContext *av)
3608
{
3609
    AVStream *st;
3610

    
3611
    /* compute default parameters */
3612
    switch(av->codec_type) {
3613
    case CODEC_TYPE_AUDIO:
3614
        if (av->bit_rate == 0)
3615
            av->bit_rate = 64000;
3616
        if (av->sample_rate == 0)
3617
            av->sample_rate = 22050;
3618
        if (av->channels == 0)
3619
            av->channels = 1;
3620
        break;
3621
    case CODEC_TYPE_VIDEO:
3622
        if (av->bit_rate == 0)
3623
            av->bit_rate = 64000;
3624
        if (av->time_base.num == 0){
3625
            av->time_base.den = 5;
3626
            av->time_base.num = 1;
3627
        }
3628
        if (av->width == 0 || av->height == 0) {
3629
            av->width = 160;
3630
            av->height = 128;
3631
        }
3632
        /* Bitrate tolerance is less for streaming */
3633
        if (av->bit_rate_tolerance == 0)
3634
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3635
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3636
        if (av->qmin == 0)
3637
            av->qmin = 3;
3638
        if (av->qmax == 0)
3639
            av->qmax = 31;
3640
        if (av->max_qdiff == 0)
3641
            av->max_qdiff = 3;
3642
        av->qcompress = 0.5;
3643
        av->qblur = 0.5;
3644

    
3645
        if (!av->nsse_weight)
3646
            av->nsse_weight = 8;
3647

    
3648
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3649
        av->me_method = ME_EPZS;
3650
        av->rc_buffer_aggressivity = 1.0;
3651

    
3652
        if (!av->rc_eq)
3653
            av->rc_eq = "tex^qComp";
3654
        if (!av->i_quant_factor)
3655
            av->i_quant_factor = -0.8;
3656
        if (!av->b_quant_factor)
3657
            av->b_quant_factor = 1.25;
3658
        if (!av->b_quant_offset)
3659
            av->b_quant_offset = 1.25;
3660
        if (!av->rc_max_rate)
3661
            av->rc_max_rate = av->bit_rate * 2;
3662

    
3663
        if (av->rc_max_rate && !av->rc_buffer_size) {
3664
            av->rc_buffer_size = av->rc_max_rate;
3665
        }
3666

    
3667

    
3668
        break;
3669
    default:
3670
        abort();
3671
    }
3672

    
3673
    st = av_mallocz(sizeof(AVStream));
3674
    if (!st)
3675
        return;
3676
    st->codec = avcodec_alloc_context();
3677
    stream->streams[stream->nb_streams++] = st;
3678
    memcpy(st->codec, av, sizeof(AVCodecContext));
3679
}
3680

    
3681
static int opt_audio_codec(const char *arg)
3682
{
3683
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3684

    
3685
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3686
        return CODEC_ID_NONE;
3687

    
3688
    return p->id;
3689
}
3690

    
3691
static int opt_video_codec(const char *arg)
3692
{
3693
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3694

    
3695
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3696
        return CODEC_ID_NONE;
3697

    
3698
    return p->id;
3699
}
3700

    
3701
/* simplistic plugin support */
3702

    
3703
#ifdef HAVE_DLOPEN
3704
static void load_module(const char *filename)
3705
{
3706
    void *dll;
3707
    void (*init_func)(void);
3708
    dll = dlopen(filename, RTLD_NOW);
3709
    if (!dll) {
3710
        fprintf(stderr, "Could not load module '%s' - %s\n",
3711
                filename, dlerror());
3712
        return;
3713
    }
3714

    
3715
    init_func = dlsym(dll, "ffserver_module_init");
3716
    if (!init_func) {
3717
        fprintf(stderr,
3718
                "%s: init function 'ffserver_module_init()' not found\n",
3719
                filename);
3720
        dlclose(dll);
3721
    }
3722

    
3723
    init_func();
3724
}
3725
#endif
3726

    
3727
static int opt_default(const char *opt, const char *arg,
3728
                       AVCodecContext *avctx, int type)
3729
{
3730
    const AVOption *o  = NULL;
3731
    const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3732
    if(o2)
3733
        o = av_set_string(avctx, opt, arg);
3734
    if(!o)
3735
        return -1;
3736
    return 0;
3737
}
3738

    
3739
static int parse_ffconfig(const char *filename)
3740
{
3741
    FILE *f;
3742
    char line[1024];
3743
    char cmd[64];
3744
    char arg[1024];
3745
    const char *p;
3746
    int val, errors, line_num;
3747
    FFStream **last_stream, *stream, *redirect;
3748
    FFStream **last_feed, *feed;
3749
    AVCodecContext audio_enc, video_enc;
3750
    int audio_id, video_id;
3751

    
3752
    f = fopen(filename, "r");
3753
    if (!f) {
3754
        perror(filename);
3755
        return -1;
3756
    }
3757

    
3758
    errors = 0;
3759
    line_num = 0;
3760
    first_stream = NULL;
3761
    last_stream = &first_stream;
3762
    first_feed = NULL;
3763
    last_feed = &first_feed;
3764
    stream = NULL;
3765
    feed = NULL;
3766
    redirect = NULL;
3767
    audio_id = CODEC_ID_NONE;
3768
    video_id = CODEC_ID_NONE;
3769
    for(;;) {
3770
        if (fgets(line, sizeof(line), f) == NULL)
3771
            break;
3772
        line_num++;
3773
        p = line;
3774
        while (isspace(*p))
3775
            p++;
3776
        if (*p == '\0' || *p == '#')
3777
            continue;
3778

    
3779
        get_arg(cmd, sizeof(cmd), &p);
3780

    
3781
        if (!strcasecmp(cmd, "Port")) {
3782
            get_arg(arg, sizeof(arg), &p);
3783
            val = atoi(arg);
3784
            if (val < 1 || val > 65536) {
3785
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3786
                        filename, line_num, arg);
3787
                errors++;
3788
            }
3789
            my_http_addr.sin_port = htons(val);
3790
        } else if (!strcasecmp(cmd, "BindAddress")) {
3791
            get_arg(arg, sizeof(arg), &p);
3792
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3793
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3794
                        filename, line_num, arg);
3795
                errors++;
3796
            }
3797
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3798
            ffserver_daemon = 0;
3799
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3800
            get_arg(arg, sizeof(arg), &p);
3801
            val = atoi(arg);
3802
            if (val < 1 || val > 65536) {
3803
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3804
                        filename, line_num, arg);
3805
                errors++;
3806
            }
3807
            my_rtsp_addr.sin_port = htons(atoi(arg));
3808
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3809
            get_arg(arg, sizeof(arg), &p);
3810
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3811
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3812
                        filename, line_num, arg);
3813
                errors++;
3814
            }
3815
        } else if (!strcasecmp(cmd, "MaxClients")) {
3816
            get_arg(arg, sizeof(arg), &p);
3817
            val = atoi(arg);
3818
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3819
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3820
                        filename, line_num, arg);
3821
                errors++;
3822
            } else {
3823
                nb_max_connections = val;
3824
            }
3825
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3826
            int64_t llval;
3827
            get_arg(arg, sizeof(arg), &p);
3828
            llval = atoll(arg);
3829
            if (llval < 10 || llval > 10000000) {
3830
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3831
                        filename, line_num, arg);
3832
                errors++;
3833
            } else
3834
                max_bandwidth = llval;
3835
        } else if (!strcasecmp(cmd, "CustomLog")) {
3836
            if (!ffserver_debug)
3837
                get_arg(logfilename, sizeof(logfilename), &p);
3838
        } else if (!strcasecmp(cmd, "<Feed")) {
3839
            /*********************************************/
3840
            /* Feed related options */
3841
            char *q;
3842
            if (stream || feed) {
3843
                fprintf(stderr, "%s:%d: Already in a tag\n",
3844
                        filename, line_num);
3845
            } else {
3846
                feed = av_mallocz(sizeof(FFStream));
3847
                /* add in stream list */
3848
                *last_stream = feed;
3849
                last_stream = &feed->next;
3850
                /* add in feed list */
3851
                *last_feed = feed;
3852
                last_feed = &feed->next_feed;
3853

    
3854
                get_arg(feed->filename, sizeof(feed->filename), &p);
3855
                q = strrchr(feed->filename, '>');
3856
                if (*q)
3857
                    *q = '\0';
3858
                feed->fmt = guess_format("ffm", NULL, NULL);
3859
                /* defaut feed file */
3860
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3861
                         "/tmp/%s.ffm", feed->filename);
3862
                feed->feed_max_size = 5 * 1024 * 1024;
3863
                feed->is_feed = 1;
3864
                feed->feed = feed; /* self feeding :-) */
3865
            }
3866
        } else if (!strcasecmp(cmd, "Launch")) {
3867
            if (feed) {
3868
                int i;
3869

    
3870
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3871

    
3872
                for (i = 0; i < 62; i++) {
3873
                    get_arg(arg, sizeof(arg), &p);
3874
                    if (!arg[0])
3875
                        break;
3876

    
3877
                    feed->child_argv[i] = av_strdup(arg);
3878
                }
3879

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

    
3882
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3883
                    "http://%s:%d/%s",
3884
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3885
                    inet_ntoa(my_http_addr.sin_addr),
3886
                    ntohs(my_http_addr.sin_port), feed->filename);
3887

    
3888
                if (ffserver_debug)
3889
                {
3890
                    int j;
3891
                    fprintf(stdout, "Launch commandline: ");
3892
                    for (j = 0; j <= i; j++)
3893
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3894
                    fprintf(stdout, "\n");
3895
                }
3896
            }
3897
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3898
            if (feed) {
3899
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3900
                feed->readonly = 1;
3901
            } else if (stream) {
3902
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3903
            }
3904
        } else if (!strcasecmp(cmd, "File")) {
3905
            if (feed) {
3906
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3907
            } else if (stream)
3908
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3909
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3910
            if (feed) {
3911
                char *p1;
3912
                double fsize;
3913

    
3914
                get_arg(arg, sizeof(arg), &p);
3915
                p1 = arg;
3916
                fsize = strtod(p1, &p1);
3917
                switch(toupper(*p1)) {
3918
                case 'K':
3919
                    fsize *= 1024;
3920
                    break;
3921
                case 'M':
3922
                    fsize *= 1024 * 1024;
3923
                    break;
3924
                case 'G':
3925
                    fsize *= 1024 * 1024 * 1024;
3926
                    break;
3927
                }
3928
                feed->feed_max_size = (int64_t)fsize;
3929
            }
3930
        } else if (!strcasecmp(cmd, "</Feed>")) {
3931
            if (!feed) {
3932
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3933
                        filename, line_num);
3934
                errors++;
3935
            }
3936
            feed = NULL;
3937
        } else if (!strcasecmp(cmd, "<Stream")) {
3938
            /*********************************************/
3939
            /* Stream related options */
3940
            char *q;
3941
            if (stream || feed) {
3942
                fprintf(stderr, "%s:%d: Already in a tag\n",
3943
                        filename, line_num);
3944
            } else {
3945
                const AVClass *class;
3946
                stream = av_mallocz(sizeof(FFStream));
3947
                *last_stream = stream;
3948
                last_stream = &stream->next;
3949

    
3950
                get_arg(stream->filename, sizeof(stream->filename), &p);
3951
                q = strrchr(stream->filename, '>');
3952
                if (*q)
3953
                    *q = '\0';
3954
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3955
                /* fetch avclass so AVOption works
3956
                 * FIXME try to use avcodec_get_context_defaults2
3957
                 * without changing defaults too much */
3958
                avcodec_get_context_defaults(&video_enc);
3959
                class = video_enc.av_class;
3960
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3961
                memset(&video_enc, 0, sizeof(AVCodecContext));
3962
                audio_enc.av_class = class;
3963
                video_enc.av_class = class;
3964
                audio_id = CODEC_ID_NONE;
3965
                video_id = CODEC_ID_NONE;
3966
                if (stream->fmt) {
3967
                    audio_id = stream->fmt->audio_codec;
3968
                    video_id = stream->fmt->video_codec;
3969
                }
3970
            }
3971
        } else if (!strcasecmp(cmd, "Feed")) {
3972
            get_arg(arg, sizeof(arg), &p);
3973
            if (stream) {
3974
                FFStream *sfeed;
3975

    
3976
                sfeed = first_feed;
3977
                while (sfeed != NULL) {
3978
                    if (!strcmp(sfeed->filename, arg))
3979
                        break;
3980
                    sfeed = sfeed->next_feed;
3981
                }
3982
                if (!sfeed)
3983
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3984
                            filename, line_num, arg);
3985
                else
3986
                    stream->feed = sfeed;
3987
            }
3988
        } else if (!strcasecmp(cmd, "Format")) {
3989
            get_arg(arg, sizeof(arg), &p);
3990
            if (stream) {
3991
            if (!strcmp(arg, "status")) {
3992
                stream->stream_type = STREAM_TYPE_STATUS;
3993
                stream->fmt = NULL;
3994
            } else {
3995
                stream->stream_type = STREAM_TYPE_LIVE;
3996
                /* jpeg cannot be used here, so use single frame jpeg */
3997
                if (!strcmp(arg, "jpeg"))
3998
                    strcpy(arg, "mjpeg");
3999
                stream->fmt = guess_stream_format(arg, NULL, NULL);
4000
                if (!stream->fmt) {
4001
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4002
                            filename, line_num, arg);
4003
                    errors++;
4004
                }
4005
            }
4006
            if (stream->fmt) {
4007
                audio_id = stream->fmt->audio_codec;
4008
                video_id = stream->fmt->video_codec;
4009
            }
4010
            }
4011
        } else if (!strcasecmp(cmd, "InputFormat")) {
4012
            get_arg(arg, sizeof(arg), &p);
4013
            stream->ifmt = av_find_input_format(arg);
4014
            if (!stream->ifmt) {
4015
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4016
                        filename, line_num, arg);
4017
            }
4018
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4019
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4020
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4021
            } else {
4022
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4023
                            filename, line_num);
4024
                errors++;
4025
            }
4026
        } else if (!strcasecmp(cmd, "Author")) {
4027
            if (stream)
4028
                get_arg(stream->author, sizeof(stream->author), &p);
4029
        } else if (!strcasecmp(cmd, "Comment")) {
4030
            if (stream)
4031
                get_arg(stream->comment, sizeof(stream->comment), &p);
4032
        } else if (!strcasecmp(cmd, "Copyright")) {
4033
            if (stream)
4034
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4035
        } else if (!strcasecmp(cmd, "Title")) {
4036
            if (stream)
4037
                get_arg(stream->title, sizeof(stream->title), &p);
4038
        } else if (!strcasecmp(cmd, "Preroll")) {
4039
            get_arg(arg, sizeof(arg), &p);
4040
            if (stream)
4041
                stream->prebuffer = atof(arg) * 1000;
4042
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4043
            if (stream)
4044
                stream->send_on_key = 1;
4045
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4046
            get_arg(arg, sizeof(arg), &p);
4047
            audio_id = opt_audio_codec(arg);
4048
            if (audio_id == CODEC_ID_NONE) {
4049
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4050
                        filename, line_num, arg);
4051
                errors++;
4052
            }
4053
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4054
            get_arg(arg, sizeof(arg), &p);
4055
            video_id = opt_video_codec(arg);
4056
            if (video_id == CODEC_ID_NONE) {
4057
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4058
                        filename, line_num, arg);
4059
                errors++;
4060
            }
4061
        } else if (!strcasecmp(cmd, "MaxTime")) {
4062
            get_arg(arg, sizeof(arg), &p);
4063
            if (stream)
4064
                stream->max_time = atof(arg) * 1000;
4065
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4066
            get_arg(arg, sizeof(arg), &p);
4067
            if (stream)
4068
                audio_enc.bit_rate = atoi(arg) * 1000;
4069
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4070
            get_arg(arg, sizeof(arg), &p);
4071
            if (stream)
4072
                audio_enc.channels = atoi(arg);
4073
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4074
            get_arg(arg, sizeof(arg), &p);
4075
            if (stream)
4076
                audio_enc.sample_rate = atoi(arg);
4077
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4078
            get_arg(arg, sizeof(arg), &p);
4079
            if (stream) {
4080
//                audio_enc.quality = atof(arg) * 1000;
4081
            }
4082
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4083
            if (stream) {
4084
                int minrate, maxrate;
4085

    
4086
                get_arg(arg, sizeof(arg), &p);
4087

    
4088
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4089
                    video_enc.rc_min_rate = minrate * 1000;
4090
                    video_enc.rc_max_rate = maxrate * 1000;
4091
                } else {
4092
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4093
                            filename, line_num, arg);
4094
                    errors++;
4095
                }
4096
            }
4097
        } else if (!strcasecmp(cmd, "Debug")) {
4098
            if (stream) {
4099
                get_arg(arg, sizeof(arg), &p);
4100
                video_enc.debug = strtol(arg,0,0);
4101
            }
4102
        } else if (!strcasecmp(cmd, "Strict")) {
4103
            if (stream) {
4104
                get_arg(arg, sizeof(arg), &p);
4105
                video_enc.strict_std_compliance = atoi(arg);
4106
            }
4107
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4108
            if (stream) {
4109
                get_arg(arg, sizeof(arg), &p);
4110
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4111
            }
4112
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4113
            if (stream) {
4114
                get_arg(arg, sizeof(arg), &p);
4115
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4116
            }
4117
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4118
            get_arg(arg, sizeof(arg), &p);
4119
            if (stream) {
4120
                video_enc.bit_rate = atoi(arg) * 1000;
4121
            }
4122
        } else if (!strcasecmp(cmd, "VideoSize")) {
4123
            get_arg(arg, sizeof(arg), &p);
4124
            if (stream) {
4125
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4126
                if ((video_enc.width % 16) != 0 ||
4127
                    (video_enc.height % 16) != 0) {
4128
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4129
                            filename, line_num);
4130
                    errors++;
4131
                }
4132
            }
4133
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4134
            get_arg(arg, sizeof(arg), &p);
4135
            if (stream) {
4136
                AVRational frame_rate;
4137
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4138
                    fprintf(stderr, "Incorrect frame rate\n");
4139
                    errors++;
4140
                } else {
4141
                    video_enc.time_base.num = frame_rate.den;
4142
                    video_enc.time_base.den = frame_rate.num;
4143
                }
4144
            }
4145
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4146
            get_arg(arg, sizeof(arg), &p);
4147
            if (stream)
4148
                video_enc.gop_size = atoi(arg);
4149
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4150
            if (stream)
4151
                video_enc.gop_size = 1;
4152
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4153
            if (stream)
4154
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4155
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4156
            if (stream) {
4157
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4158
                video_enc.flags |= CODEC_FLAG_4MV;
4159
            }
4160
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4161
                   !strcasecmp(cmd, "AVOptionAudio")) {
4162
            char arg2[1024];
4163
            AVCodecContext *avctx;
4164
            int type;
4165
            get_arg(arg, sizeof(arg), &p);
4166
            get_arg(arg2, sizeof(arg2), &p);
4167
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4168
                avctx = &video_enc;
4169
                type = AV_OPT_FLAG_VIDEO_PARAM;
4170
            } else {
4171
                avctx = &audio_enc;
4172
                type = AV_OPT_FLAG_AUDIO_PARAM;
4173
            }
4174
            if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4175
                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4176
                errors++;
4177
            }
4178
        } else if (!strcasecmp(cmd, "VideoTag")) {
4179
            get_arg(arg, sizeof(arg), &p);
4180
            if ((strlen(arg) == 4) && stream)
4181
                video_enc.codec_tag = ff_get_fourcc(arg);
4182
        } else if (!strcasecmp(cmd, "BitExact")) {
4183
            if (stream)
4184
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4185
        } else if (!strcasecmp(cmd, "DctFastint")) {
4186
            if (stream)
4187
                video_enc.dct_algo  = FF_DCT_FASTINT;
4188
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4189
            if (stream)
4190
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4191
        } else if (!strcasecmp(cmd, "Qscale")) {
4192
            get_arg(arg, sizeof(arg), &p);
4193
            if (stream) {
4194
                video_enc.flags |= CODEC_FLAG_QSCALE;
4195
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4196
            }
4197
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4198
            get_arg(arg, sizeof(arg), &p);
4199
            if (stream) {
4200
                video_enc.max_qdiff = atoi(arg);
4201
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4202
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4203
                            filename, line_num);
4204
                    errors++;
4205
                }
4206
            }
4207
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4208
            get_arg(arg, sizeof(arg), &p);
4209
            if (stream) {
4210
                video_enc.qmax = atoi(arg);
4211
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4212
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4213
                            filename, line_num);
4214
                    errors++;
4215
                }
4216
            }
4217
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4218
            get_arg(arg, sizeof(arg), &p);
4219
            if (stream) {
4220
                video_enc.qmin = atoi(arg);
4221
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4222
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4223
                            filename, line_num);
4224
                    errors++;
4225
                }
4226
            }
4227
        } else if (!strcasecmp(cmd, "LumaElim")) {
4228
            get_arg(arg, sizeof(arg), &p);
4229
            if (stream)
4230
                video_enc.luma_elim_threshold = atoi(arg);
4231
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4232
            get_arg(arg, sizeof(arg), &p);
4233
            if (stream)
4234
                video_enc.chroma_elim_threshold = atoi(arg);
4235
        } else if (!strcasecmp(cmd, "LumiMask")) {
4236
            get_arg(arg, sizeof(arg), &p);
4237
            if (stream)
4238
                video_enc.lumi_masking = atof(arg);
4239
        } else if (!strcasecmp(cmd, "DarkMask")) {
4240
            get_arg(arg, sizeof(arg), &p);
4241
            if (stream)
4242
                video_enc.dark_masking = atof(arg);
4243
        } else if (!strcasecmp(cmd, "NoVideo")) {
4244
            video_id = CODEC_ID_NONE;
4245
        } else if (!strcasecmp(cmd, "NoAudio")) {
4246
            audio_id = CODEC_ID_NONE;
4247
        } else if (!strcasecmp(cmd, "ACL")) {
4248
            IPAddressACL acl;
4249

    
4250
            get_arg(arg, sizeof(arg), &p);
4251
            if (strcasecmp(arg, "allow") == 0)
4252
                acl.action = IP_ALLOW;
4253
            else if (strcasecmp(arg, "deny") == 0)
4254
                acl.action = IP_DENY;
4255
            else {
4256
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4257
                        filename, line_num, arg);
4258
                errors++;
4259
            }
4260

    
4261
            get_arg(arg, sizeof(arg), &p);
4262

    
4263
            if (resolve_host(&acl.first, arg) != 0) {
4264
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4265
                        filename, line_num, arg);
4266
                errors++;
4267
            } else
4268
                acl.last = acl.first;
4269

    
4270
            get_arg(arg, sizeof(arg), &p);
4271

    
4272
            if (arg[0]) {
4273
                if (resolve_host(&acl.last, arg) != 0) {
4274
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4275
                            filename, line_num, arg);
4276
                    errors++;
4277
                }
4278
            }
4279

    
4280
            if (!errors) {
4281
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4282
                IPAddressACL **naclp = 0;
4283

    
4284
                acl.next = 0;
4285
                *nacl = acl;
4286

    
4287
                if (stream)
4288
                    naclp = &stream->acl;
4289
                else if (feed)
4290
                    naclp = &feed->acl;
4291
                else {
4292
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4293
                            filename, line_num);
4294
                    errors++;
4295
                }
4296

    
4297
                if (naclp) {
4298
                    while (*naclp)
4299
                        naclp = &(*naclp)->next;
4300

    
4301
                    *naclp = nacl;
4302
                }
4303
            }
4304
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4305
            get_arg(arg, sizeof(arg), &p);
4306
            if (stream) {
4307
                av_freep(&stream->rtsp_option);
4308
                stream->rtsp_option = av_strdup(arg);
4309
            }
4310
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4311
            get_arg(arg, sizeof(arg), &p);
4312
            if (stream) {
4313
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4314
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4315
                            filename, line_num, arg);
4316
                    errors++;
4317
                }
4318
                stream->is_multicast = 1;
4319
                stream->loop = 1; /* default is looping */
4320
            }
4321
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4322
            get_arg(arg, sizeof(arg), &p);
4323
            if (stream)
4324
                stream->multicast_port = atoi(arg);
4325
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4326
            get_arg(arg, sizeof(arg), &p);
4327
            if (stream)
4328
                stream->multicast_ttl = atoi(arg);
4329
        } else if (!strcasecmp(cmd, "NoLoop")) {
4330
            if (stream)
4331
                stream->loop = 0;
4332
        } else if (!strcasecmp(cmd, "</Stream>")) {
4333
            if (!stream) {
4334
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4335
                        filename, line_num);
4336
                errors++;
4337
            } else {
4338
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4339
                    if (audio_id != CODEC_ID_NONE) {
4340
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4341
                        audio_enc.codec_id = audio_id;
4342
                        add_codec(stream, &audio_enc);
4343
                    }
4344
                    if (video_id != CODEC_ID_NONE) {
4345
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4346
                        video_enc.codec_id = video_id;
4347
                        add_codec(stream, &video_enc);
4348
                    }
4349
                }
4350
                stream = NULL;
4351
            }
4352
        } else if (!strcasecmp(cmd, "<Redirect")) {
4353
            /*********************************************/
4354
            char *q;
4355
            if (stream || feed || redirect) {
4356
                fprintf(stderr, "%s:%d: Already in a tag\n",
4357
                        filename, line_num);
4358
                errors++;
4359
            } else {
4360
                redirect = av_mallocz(sizeof(FFStream));
4361
                *last_stream = redirect;
4362
                last_stream = &redirect->next;
4363

    
4364
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4365
                q = strrchr(redirect->filename, '>');
4366
                if (*q)
4367
                    *q = '\0';
4368
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4369
            }
4370
        } else if (!strcasecmp(cmd, "URL")) {
4371
            if (redirect)
4372
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4373
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4374
            if (!redirect) {
4375
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4376
                        filename, line_num);
4377
                errors++;
4378
            } else {
4379
                if (!redirect->feed_filename[0]) {
4380
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4381
                            filename, line_num);
4382
                    errors++;
4383
                }
4384
                redirect = NULL;
4385
            }
4386
        } else if (!strcasecmp(cmd, "LoadModule")) {
4387
            get_arg(arg, sizeof(arg), &p);
4388
#ifdef HAVE_DLOPEN
4389
            load_module(arg);
4390
#else
4391
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4392
                    filename, line_num, arg);
4393
            errors++;
4394
#endif
4395
        } else {
4396
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4397
                    filename, line_num, cmd);
4398
            errors++;
4399
        }
4400
    }
4401

    
4402
    fclose(f);
4403
    if (errors)
4404
        return -1;
4405
    else
4406
        return 0;
4407
}
4408

    
4409
static void handle_child_exit(int sig)
4410
{
4411
    pid_t pid;
4412
    int status;
4413

    
4414
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4415
        FFStream *feed;
4416

    
4417
        for (feed = first_feed; feed; feed = feed->next) {
4418
            if (feed->pid == pid) {
4419
                int uptime = time(0) - feed->pid_start;
4420

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

    
4424
                if (uptime < 30)
4425
                    /* Turn off any more restarts */
4426
                    feed->child_argv = 0;
4427
            }
4428
        }
4429
    }
4430

    
4431
    need_to_start_children = 1;
4432
}
4433

    
4434
static void opt_debug()
4435
{
4436
    ffserver_debug = 1;
4437
    ffserver_daemon = 0;
4438
    logfilename[0] = '-';
4439
}
4440

    
4441
static void opt_show_help(void)
4442
{
4443
    printf("usage: ffserver [options]\n"
4444
           "Hyper fast multi format Audio/Video streaming server\n");
4445
    printf("\n");
4446
    show_help_options(options, "Main options:\n", 0, 0);
4447
}
4448

    
4449
static const OptionDef options[] = {
4450
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4451
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4452
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4453
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4454
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4455
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4456
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4457
    { NULL },
4458
};
4459

    
4460
int main(int argc, char **argv)
4461
{
4462
    struct sigaction sigact;
4463

    
4464
    av_register_all();
4465

    
4466
    show_banner();
4467

    
4468
    config_filename = "/etc/ffserver.conf";
4469

    
4470
    my_program_name = argv[0];
4471
    my_program_dir = getcwd(0, 0);
4472
    ffserver_daemon = 1;
4473

    
4474
    parse_options(argc, argv, options, NULL);
4475

    
4476
    unsetenv("http_proxy");             /* Kill the http_proxy */
4477

    
4478
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4479

    
4480
    memset(&sigact, 0, sizeof(sigact));
4481
    sigact.sa_handler = handle_child_exit;
4482
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4483
    sigaction(SIGCHLD, &sigact, 0);
4484

    
4485
    if (parse_ffconfig(config_filename) < 0) {
4486
        fprintf(stderr, "Incorrect config file - exiting.\n");
4487
        exit(1);
4488
    }
4489

    
4490
    build_file_streams();
4491

    
4492
    build_feed_streams();
4493

    
4494
    compute_bandwidth();
4495

    
4496
    /* put the process in background and detach it from its TTY */
4497
    if (ffserver_daemon) {
4498
        int pid;
4499

    
4500
        pid = fork();
4501
        if (pid < 0) {
4502
            perror("fork");
4503
            exit(1);
4504
        } else if (pid > 0) {
4505
            /* parent : exit */
4506
            exit(0);
4507
        } else {
4508
            /* child */
4509
            setsid();
4510
            chdir("/");
4511
            close(0);
4512
            open("/dev/null", O_RDWR);
4513
            if (strcmp(logfilename, "-") != 0) {
4514
                close(1);
4515
                dup(0);
4516
            }
4517
            close(2);
4518
            dup(0);
4519
        }
4520
    }
4521

    
4522
    /* signal init */
4523
    signal(SIGPIPE, SIG_IGN);
4524

    
4525
    /* open log file if needed */
4526
    if (logfilename[0] != '\0') {
4527
        if (!strcmp(logfilename, "-"))
4528
            logfile = stderr;
4529
        else
4530
            logfile = fopen(logfilename, "a");
4531
        av_log_set_callback(http_av_log);
4532
    }
4533

    
4534
    if (http_server() < 0) {
4535
        http_log("Could not start server\n");
4536
        exit(1);
4537
    }
4538

    
4539
    return 0;
4540
}