Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ d80904cc

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
        for(i=0;i<c->stream->nb_streams;i++) {
2044
            AVStream *st;
2045
            AVStream *src;
2046
            st = av_mallocz(sizeof(AVStream));
2047
            c->fmt_ctx.streams[i] = st;
2048
            /* if file or feed, then just take streams from FFStream struct */
2049
            if (!c->stream->feed ||
2050
                c->stream->feed == c->stream)
2051
                src = c->stream->streams[i];
2052
            else
2053
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2054

    
2055
            *st = *src;
2056
            st->priv_data = 0;
2057
            st->codec->frame_number = 0; /* XXX: should be done in
2058
                                           AVStream, not in codec */
2059
        }
2060
        /* set output format parameters */
2061
        c->fmt_ctx.oformat = c->stream->fmt;
2062
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2063

    
2064
        c->got_key_frame = 0;
2065

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

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

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

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

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

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

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

    
2225
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2226
                    c->cur_frame_bytes = len;
2227
                    c->buffer_ptr = c->pb_buffer;
2228
                    c->buffer_end = c->pb_buffer + len;
2229

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

    
2257
        c->last_packet_sent = 1;
2258
        break;
2259
    }
2260
    return 0;
2261
}
2262

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

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

    
2299
                c->data_count += len;
2300
                update_datarate(&c->datarate, c->data_count);
2301
                if (c->stream)
2302
                    c->stream->bytes_served += len;
2303

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

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

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

    
2374
                c->data_count += len;
2375
                update_datarate(&c->datarate, c->data_count);
2376
                if (c->stream)
2377
                    c->stream->bytes_served += len;
2378
                break;
2379
            }
2380
        }
2381
    } /* for(;;) */
2382
    return 0;
2383
}
2384

    
2385
static int http_start_receive_data(HTTPContext *c)
2386
{
2387
    int fd;
2388

    
2389
    if (c->stream->feed_opened)
2390
        return -1;
2391

    
2392
    /* Don't permit writing to this one */
2393
    if (c->stream->readonly)
2394
        return -1;
2395

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

    
2404
    c->stream->feed_write_index = ffm_read_write_index(fd);
2405
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2406
    lseek(fd, 0, SEEK_SET);
2407

    
2408
    /* init buffer input */
2409
    c->buffer_ptr = c->buffer;
2410
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2411
    c->stream->feed_opened = 1;
2412
    return 0;
2413
}
2414

    
2415
static int http_receive_data(HTTPContext *c)
2416
{
2417
    HTTPContext *c1;
2418

    
2419
    if (c->buffer_end > c->buffer_ptr) {
2420
        int len;
2421

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

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

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

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

    
2460
            feed->feed_write_index += FFM_PACKET_SIZE;
2461
            /* update file size */
2462
            if (feed->feed_write_index > c->stream->feed_size)
2463
                feed->feed_size = feed->feed_write_index;
2464

    
2465
            /* handle wrap around if max file size reached */
2466
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2467
                feed->feed_write_index = FFM_PACKET_SIZE;
2468

    
2469
            /* write index */
2470
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2471

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

    
2485
            /* use feed output format name to find corresponding input format */
2486
            fmt_in = av_find_input_format(feed->fmt->name);
2487
            if (!fmt_in)
2488
                goto fail;
2489

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

    
2493
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2494
                av_free(pb);
2495
                goto fail;
2496
            }
2497

    
2498
            /* Now we have the actual streams */
2499
            if (s->nb_streams != feed->nb_streams) {
2500
                av_close_input_stream(s);
2501
                av_free(pb);
2502
                goto fail;
2503
            }
2504

    
2505
            for (i = 0; i < s->nb_streams; i++)
2506
                memcpy(feed->streams[i]->codec,
2507
                       s->streams[i]->codec, sizeof(AVCodecContext));
2508

    
2509
            av_close_input_stream(s);
2510
            av_free(pb);
2511
        }
2512
        c->buffer_ptr = c->buffer;
2513
    }
2514

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

    
2528
/********************************************************************/
2529
/* RTSP handling */
2530

    
2531
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2532
{
2533
    const char *str;
2534
    time_t ti;
2535
    char *p;
2536
    char buf2[32];
2537

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

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

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

    
2590
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2591
{
2592
    rtsp_reply_header(c, error_number);
2593
    url_fprintf(c->pb, "\r\n");
2594
}
2595

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

    
2606
    c->buffer_ptr[0] = '\0';
2607
    p = c->buffer;
2608

    
2609
    get_word(cmd, sizeof(cmd), &p);
2610
    get_word(url, sizeof(url), &p);
2611
    get_word(protocol, sizeof(protocol), &p);
2612

    
2613
    av_strlcpy(c->method, cmd, sizeof(c->method));
2614
    av_strlcpy(c->url, url, sizeof(c->url));
2615
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2616

    
2617
    if (url_open_dyn_buf(&c->pb) < 0) {
2618
        /* XXX: cannot do more */
2619
        c->pb = NULL; /* safety */
2620
        return -1;
2621
    }
2622

    
2623
    /* check version name */
2624
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2625
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2626
        goto the_end;
2627
    }
2628

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

    
2655
    /* handle sequence number */
2656
    c->seq = header->seq;
2657

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

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

    
2686
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2687
                                   struct in_addr my_ip)
2688
{
2689
    AVFormatContext *avc;
2690
    AVStream avs[MAX_STREAMS];
2691
    int i;
2692

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

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

    
2717
    return strlen(*pbuffer);
2718
}
2719

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

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

    
2738
    /* find which url is asked */
2739
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2740
    path = path1;
2741
    if (*path == '/')
2742
        path++;
2743

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

    
2755
 found:
2756
    /* prepare the media description in sdp format */
2757

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

    
2773
static HTTPContext *find_rtp_session(const char *session_id)
2774
{
2775
    HTTPContext *c;
2776

    
2777
    if (session_id[0] == '\0')
2778
        return NULL;
2779

    
2780
    for(c = first_http_ctx; c != NULL; c = c->next) {
2781
        if (!strcmp(c->session_id, session_id))
2782
            return c;
2783
    }
2784
    return NULL;
2785
}
2786

    
2787
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2788
{
2789
    RTSPTransportField *th;
2790
    int i;
2791

    
2792
    for(i=0;i<h->nb_transports;i++) {
2793
        th = &h->transports[i];
2794
        if (th->protocol == protocol)
2795
            return th;
2796
    }
2797
    return NULL;
2798
}
2799

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

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

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

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

    
2847
    /* generate session id if needed */
2848
    if (h->session_id[0] == '\0')
2849
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2850
                 av_random(&random_state), av_random(&random_state));
2851

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

    
2865
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2866
                                   th->protocol);
2867
        if (!rtp_c) {
2868
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2869
            return;
2870
        }
2871

    
2872
        /* open input stream */
2873
        if (open_input_stream(rtp_c, "") < 0) {
2874
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2875
            return;
2876
        }
2877
    }
2878

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

    
2886
    /* test if stream is already set up */
2887
    if (rtp_c->rtp_ctx[stream_index]) {
2888
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2889
        return;
2890
    }
2891

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

    
2900
    /* setup default options */
2901
    setup.transport_option[0] = '\0';
2902
    dest_addr = rtp_c->from_addr;
2903
    dest_addr.sin_port = htons(th->client_port_min);
2904

    
2905
    /* setup stream */
2906
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2907
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2908
        return;
2909
    }
2910

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

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

    
2935

    
2936
    url_fprintf(c->pb, "\r\n");
2937
}
2938

    
2939

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

    
2951
    rtp_c = find_rtp_session(session_id);
2952
    if (!rtp_c)
2953
        return NULL;
2954

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

    
2972
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2973
{
2974
    HTTPContext *rtp_c;
2975

    
2976
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2977
    if (!rtp_c) {
2978
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2979
        return;
2980
    }
2981

    
2982
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2983
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2984
        rtp_c->state != HTTPSTATE_READY) {
2985
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2986
        return;
2987
    }
2988

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

    
2997
    rtp_c->state = HTTPSTATE_SEND_DATA;
2998

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

    
3006
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3007
{
3008
    HTTPContext *rtp_c;
3009

    
3010
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3011
    if (!rtp_c) {
3012
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3013
        return;
3014
    }
3015

    
3016
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3017
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3018
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3019
        return;
3020
    }
3021

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

    
3031
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3032
{
3033
    HTTPContext *rtp_c;
3034
    char session_id[32];
3035

    
3036
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3037
    if (!rtp_c) {
3038
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3039
        return;
3040
    }
3041

    
3042
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3043

    
3044
    /* abort the session */
3045
    close_connection(rtp_c);
3046

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

    
3054

    
3055
/********************************************************************/
3056
/* RTP handling */
3057

    
3058
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3059
                                       FFStream *stream, const char *session_id,
3060
                                       enum RTSPProtocol rtp_protocol)
3061
{
3062
    HTTPContext *c = NULL;
3063
    const char *proto_str;
3064

    
3065
    /* XXX: should output a warning page when coming
3066
       close to the connection limit */
3067
    if (nb_connections >= nb_max_connections)
3068
        goto fail;
3069

    
3070
    /* add a new connection */
3071
    c = av_mallocz(sizeof(HTTPContext));
3072
    if (!c)
3073
        goto fail;
3074

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

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

    
3107
    current_bandwidth += stream->bandwidth;
3108

    
3109
    c->next = first_http_ctx;
3110
    first_http_ctx = c;
3111
    return c;
3112

    
3113
 fail:
3114
    if (c) {
3115
        av_free(c->buffer);
3116
        av_free(c);
3117
    }
3118
    return NULL;
3119
}
3120

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

    
3135
    /* now we can open the relevant output stream */
3136
    ctx = av_alloc_format_context();
3137
    if (!ctx)
3138
        return -1;
3139
    ctx->oformat = guess_format("rtp", NULL, NULL);
3140

    
3141
    st = av_mallocz(sizeof(AVStream));
3142
    if (!st)
3143
        goto fail;
3144
    st->codec= avcodec_alloc_context();
3145
    ctx->nb_streams = 1;
3146
    ctx->streams[0] = st;
3147

    
3148
    if (!c->stream->feed ||
3149
        c->stream->feed == c->stream)
3150
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3151
    else
3152
        memcpy(st,
3153
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3154
               sizeof(AVStream));
3155
    st->priv_data = NULL;
3156

    
3157
    /* build destination RTP address */
3158
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3159

    
3160
    switch(c->rtp_protocol) {
3161
    case RTSP_PROTOCOL_RTP_UDP:
3162
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3163
        /* RTP/UDP case */
3164

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

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

    
3193
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3194
             ipaddr, ntohs(dest_addr->sin_port),
3195
             c->stream->filename, stream_index, c->protocol);
3196

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

    
3213
    c->rtp_ctx[stream_index] = ctx;
3214
    return 0;
3215
}
3216

    
3217
/********************************************************************/
3218
/* ffserver initialization */
3219

    
3220
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3221
{
3222
    AVStream *fst;
3223

    
3224
    fst = av_mallocz(sizeof(AVStream));
3225
    if (!fst)
3226
        return NULL;
3227
    fst->codec= avcodec_alloc_context();
3228
    fst->priv_data = av_mallocz(sizeof(FeedData));
3229
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3230
    fst->index = stream->nb_streams;
3231
    av_set_pts_info(fst, 33, 1, 90000);
3232
    stream->streams[stream->nb_streams++] = fst;
3233
    return fst;
3234
}
3235

    
3236
/* return the stream number in the feed */
3237
static int add_av_stream(FFStream *feed, AVStream *st)
3238
{
3239
    AVStream *fst;
3240
    AVCodecContext *av, *av1;
3241
    int i;
3242

    
3243
    av = st->codec;
3244
    for(i=0;i<feed->nb_streams;i++) {
3245
        st = feed->streams[i];
3246
        av1 = st->codec;
3247
        if (av1->codec_id == av->codec_id &&
3248
            av1->codec_type == av->codec_type &&
3249
            av1->bit_rate == av->bit_rate) {
3250

    
3251
            switch(av->codec_type) {
3252
            case CODEC_TYPE_AUDIO:
3253
                if (av1->channels == av->channels &&
3254
                    av1->sample_rate == av->sample_rate)
3255
                    goto found;
3256
                break;
3257
            case CODEC_TYPE_VIDEO:
3258
                if (av1->width == av->width &&
3259
                    av1->height == av->height &&
3260
                    av1->time_base.den == av->time_base.den &&
3261
                    av1->time_base.num == av->time_base.num &&
3262
                    av1->gop_size == av->gop_size)
3263
                    goto found;
3264
                break;
3265
            default:
3266
                abort();
3267
            }
3268
        }
3269
    }
3270

    
3271
    fst = add_av_stream1(feed, av);
3272
    if (!fst)
3273
        return -1;
3274
    return feed->nb_streams - 1;
3275
 found:
3276
    return i;
3277
}
3278

    
3279
static void remove_stream(FFStream *stream)
3280
{
3281
    FFStream **ps;
3282
    ps = &first_stream;
3283
    while (*ps != NULL) {
3284
        if (*ps == stream)
3285
            *ps = (*ps)->next;
3286
        else
3287
            ps = &(*ps)->next;
3288
    }
3289
}
3290

    
3291
/* specific mpeg4 handling : we extract the raw parameters */
3292
static void extract_mpeg4_header(AVFormatContext *infile)
3293
{
3294
    int mpeg4_count, i, size;
3295
    AVPacket pkt;
3296
    AVStream *st;
3297
    const uint8_t *p;
3298

    
3299
    mpeg4_count = 0;
3300
    for(i=0;i<infile->nb_streams;i++) {
3301
        st = infile->streams[i];
3302
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3303
            st->codec->extradata_size == 0) {
3304
            mpeg4_count++;
3305
        }
3306
    }
3307
    if (!mpeg4_count)
3308
        return;
3309

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

    
3340
/* compute the needed AVStream for each file */
3341
static void build_file_streams(void)
3342
{
3343
    FFStream *stream, *stream_next;
3344
    AVFormatContext *infile;
3345
    int i, ret;
3346

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

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

    
3380
                for(i=0;i<infile->nb_streams;i++)
3381
                    add_av_stream1(stream, infile->streams[i]->codec);
3382

    
3383
                av_close_input_file(infile);
3384
            }
3385
        }
3386
    }
3387
}
3388

    
3389
/* compute the needed AVStream for each feed */
3390
static void build_feed_streams(void)
3391
{
3392
    FFStream *stream, *feed;
3393
    int i;
3394

    
3395
    /* gather all streams */
3396
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3397
        feed = stream->feed;
3398
        if (feed) {
3399
            if (!stream->is_feed) {
3400
                /* we handle a stream coming from a feed */
3401
                for(i=0;i<stream->nb_streams;i++)
3402
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3403
            }
3404
        }
3405
    }
3406

    
3407
    /* gather all streams */
3408
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3409
        feed = stream->feed;
3410
        if (feed) {
3411
            if (stream->is_feed) {
3412
                for(i=0;i<stream->nb_streams;i++)
3413
                    stream->feed_streams[i] = i;
3414
            }
3415
        }
3416
    }
3417

    
3418
    /* create feed files if needed */
3419
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3420
        int fd;
3421

    
3422
        if (url_exist(feed->feed_filename)) {
3423
            /* See if it matches */
3424
            AVFormatContext *s;
3425
            int matches = 0;
3426

    
3427
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3428
                /* Now see if it matches */
3429
                if (s->nb_streams == feed->nb_streams) {
3430
                    matches = 1;
3431
                    for(i=0;i<s->nb_streams;i++) {
3432
                        AVStream *sf, *ss;
3433
                        sf = feed->streams[i];
3434
                        ss = s->streams[i];
3435

    
3436
                        if (sf->index != ss->index ||
3437
                            sf->id != ss->id) {
3438
                            printf("Index & Id do not match for stream %d (%s)\n",
3439
                                   i, feed->feed_filename);
3440
                            matches = 0;
3441
                        } else {
3442
                            AVCodecContext *ccf, *ccs;
3443

    
3444
                            ccf = sf->codec;
3445
                            ccs = ss->codec;
3446
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3447

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

    
3481
                av_close_input_file(s);
3482
            } else
3483
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3484
                        feed->feed_filename);
3485

    
3486
            if (!matches) {
3487
                if (feed->readonly) {
3488
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3489
                        feed->feed_filename);
3490
                    exit(1);
3491
                }
3492
                unlink(feed->feed_filename);
3493
            }
3494
        }
3495
        if (!url_exist(feed->feed_filename)) {
3496
            AVFormatContext s1, *s = &s1;
3497

    
3498
            if (feed->readonly) {
3499
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3500
                    feed->feed_filename);
3501
                exit(1);
3502
            }
3503

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

    
3534
        feed->feed_write_index = ffm_read_write_index(fd);
3535
        feed->feed_size = lseek(fd, 0, SEEK_END);
3536
        /* ensure that we do not wrap before the end of file */
3537
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3538
            feed->feed_max_size = feed->feed_size;
3539

    
3540
        close(fd);
3541
    }
3542
}
3543

    
3544
/* compute the bandwidth used by each stream */
3545
static void compute_bandwidth(void)
3546
{
3547
    unsigned bandwidth;
3548
    int i;
3549
    FFStream *stream;
3550

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

    
3568
static void get_arg(char *buf, int buf_size, const char **pp)
3569
{
3570
    const char *p;
3571
    char *q;
3572
    int quote;
3573

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

    
3600
/* add a codec and set the default parameters */
3601
static void add_codec(FFStream *stream, AVCodecContext *av)
3602
{
3603
    AVStream *st;
3604

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

    
3639
        if (!av->nsse_weight)
3640
            av->nsse_weight = 8;
3641

    
3642
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3643
        av->me_method = ME_EPZS;
3644
        av->rc_buffer_aggressivity = 1.0;
3645

    
3646
        if (!av->rc_eq)
3647
            av->rc_eq = "tex^qComp";
3648
        if (!av->i_quant_factor)
3649
            av->i_quant_factor = -0.8;
3650
        if (!av->b_quant_factor)
3651
            av->b_quant_factor = 1.25;
3652
        if (!av->b_quant_offset)
3653
            av->b_quant_offset = 1.25;
3654
        if (!av->rc_max_rate)
3655
            av->rc_max_rate = av->bit_rate * 2;
3656

    
3657
        if (av->rc_max_rate && !av->rc_buffer_size) {
3658
            av->rc_buffer_size = av->rc_max_rate;
3659
        }
3660

    
3661

    
3662
        break;
3663
    default:
3664
        abort();
3665
    }
3666

    
3667
    st = av_mallocz(sizeof(AVStream));
3668
    if (!st)
3669
        return;
3670
    st->codec = avcodec_alloc_context();
3671
    stream->streams[stream->nb_streams++] = st;
3672
    memcpy(st->codec, av, sizeof(AVCodecContext));
3673
}
3674

    
3675
static int opt_audio_codec(const char *arg)
3676
{
3677
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3678

    
3679
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3680
        return CODEC_ID_NONE;
3681

    
3682
    return p->id;
3683
}
3684

    
3685
static int opt_video_codec(const char *arg)
3686
{
3687
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3688

    
3689
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3690
        return CODEC_ID_NONE;
3691

    
3692
    return p->id;
3693
}
3694

    
3695
/* simplistic plugin support */
3696

    
3697
#ifdef HAVE_DLOPEN
3698
static void load_module(const char *filename)
3699
{
3700
    void *dll;
3701
    void (*init_func)(void);
3702
    dll = dlopen(filename, RTLD_NOW);
3703
    if (!dll) {
3704
        fprintf(stderr, "Could not load module '%s' - %s\n",
3705
                filename, dlerror());
3706
        return;
3707
    }
3708

    
3709
    init_func = dlsym(dll, "ffserver_module_init");
3710
    if (!init_func) {
3711
        fprintf(stderr,
3712
                "%s: init function 'ffserver_module_init()' not found\n",
3713
                filename);
3714
        dlclose(dll);
3715
    }
3716

    
3717
    init_func();
3718
}
3719
#endif
3720

    
3721
static int opt_default(const char *opt, const char *arg,
3722
                       AVCodecContext *avctx, int type)
3723
{
3724
    const AVOption *o  = NULL;
3725
    const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3726
    if(o2)
3727
        o = av_set_string(avctx, opt, arg);
3728
    if(!o)
3729
        return -1;
3730
    return 0;
3731
}
3732

    
3733
static int parse_ffconfig(const char *filename)
3734
{
3735
    FILE *f;
3736
    char line[1024];
3737
    char cmd[64];
3738
    char arg[1024];
3739
    const char *p;
3740
    int val, errors, line_num;
3741
    FFStream **last_stream, *stream, *redirect;
3742
    FFStream **last_feed, *feed;
3743
    AVCodecContext audio_enc, video_enc;
3744
    int audio_id, video_id;
3745

    
3746
    f = fopen(filename, "r");
3747
    if (!f) {
3748
        perror(filename);
3749
        return -1;
3750
    }
3751

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

    
3773
        get_arg(cmd, sizeof(cmd), &p);
3774

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

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

    
3864
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3865

    
3866
                for (i = 0; i < 62; i++) {
3867
                    get_arg(arg, sizeof(arg), &p);
3868
                    if (!arg[0])
3869
                        break;
3870

    
3871
                    feed->child_argv[i] = av_strdup(arg);
3872
                }
3873

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

    
3876
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3877
                    "http://%s:%d/%s",
3878
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3879
                    inet_ntoa(my_http_addr.sin_addr),
3880
                    ntohs(my_http_addr.sin_port), feed->filename);
3881

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

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

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

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

    
4080
                get_arg(arg, sizeof(arg), &p);
4081

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

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

    
4255
            get_arg(arg, sizeof(arg), &p);
4256

    
4257
            if (resolve_host(&acl.first, arg) != 0) {
4258
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4259
                        filename, line_num, arg);
4260
                errors++;
4261
            } else
4262
                acl.last = acl.first;
4263

    
4264
            get_arg(arg, sizeof(arg), &p);
4265

    
4266
            if (arg[0]) {
4267
                if (resolve_host(&acl.last, arg) != 0) {
4268
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4269
                            filename, line_num, arg);
4270
                    errors++;
4271
                }
4272
            }
4273

    
4274
            if (!errors) {
4275
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4276
                IPAddressACL **naclp = 0;
4277

    
4278
                acl.next = 0;
4279
                *nacl = acl;
4280

    
4281
                if (stream)
4282
                    naclp = &stream->acl;
4283
                else if (feed)
4284
                    naclp = &feed->acl;
4285
                else {
4286
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4287
                            filename, line_num);
4288
                    errors++;
4289
                }
4290

    
4291
                if (naclp) {
4292
                    while (*naclp)
4293
                        naclp = &(*naclp)->next;
4294

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

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

    
4396
    fclose(f);
4397
    if (errors)
4398
        return -1;
4399
    else
4400
        return 0;
4401
}
4402

    
4403
static void handle_child_exit(int sig)
4404
{
4405
    pid_t pid;
4406
    int status;
4407

    
4408
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4409
        FFStream *feed;
4410

    
4411
        for (feed = first_feed; feed; feed = feed->next) {
4412
            if (feed->pid == pid) {
4413
                int uptime = time(0) - feed->pid_start;
4414

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

    
4418
                if (uptime < 30)
4419
                    /* Turn off any more restarts */
4420
                    feed->child_argv = 0;
4421
            }
4422
        }
4423
    }
4424

    
4425
    need_to_start_children = 1;
4426
}
4427

    
4428
static void opt_debug()
4429
{
4430
    ffserver_debug = 1;
4431
    ffserver_daemon = 0;
4432
    logfilename[0] = '-';
4433
}
4434

    
4435
static void opt_show_help(void)
4436
{
4437
    printf("usage: ffserver [options]\n"
4438
           "Hyper fast multi format Audio/Video streaming server\n");
4439
    printf("\n");
4440
    show_help_options(options, "Main options:\n", 0, 0);
4441
}
4442

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

    
4454
int main(int argc, char **argv)
4455
{
4456
    struct sigaction sigact;
4457

    
4458
    av_register_all();
4459

    
4460
    show_banner();
4461

    
4462
    config_filename = "/etc/ffserver.conf";
4463

    
4464
    my_program_name = argv[0];
4465
    my_program_dir = getcwd(0, 0);
4466
    ffserver_daemon = 1;
4467

    
4468
    parse_options(argc, argv, options, NULL);
4469

    
4470
    unsetenv("http_proxy");             /* Kill the http_proxy */
4471

    
4472
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4473

    
4474
    memset(&sigact, 0, sizeof(sigact));
4475
    sigact.sa_handler = handle_child_exit;
4476
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4477
    sigaction(SIGCHLD, &sigact, 0);
4478

    
4479
    if (parse_ffconfig(config_filename) < 0) {
4480
        fprintf(stderr, "Incorrect config file - exiting.\n");
4481
        exit(1);
4482
    }
4483

    
4484
    build_file_streams();
4485

    
4486
    build_feed_streams();
4487

    
4488
    compute_bandwidth();
4489

    
4490
    /* put the process in background and detach it from its TTY */
4491
    if (ffserver_daemon) {
4492
        int pid;
4493

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

    
4516
    /* signal init */
4517
    signal(SIGPIPE, SIG_IGN);
4518

    
4519
    /* open log file if needed */
4520
    if (logfilename[0] != '\0') {
4521
        if (!strcmp(logfilename, "-"))
4522
            logfile = stderr;
4523
        else
4524
            logfile = fopen(logfilename, "a");
4525
        av_log_set_callback(http_av_log);
4526
    }
4527

    
4528
    if (http_server() < 0) {
4529
        http_log("Could not start server\n");
4530
        exit(1);
4531
    }
4532

    
4533
    return 0;
4534
}