Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 14c43f91

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
        http_log("feed %s already being received\n", stream->feed_filename);
1345
        goto send_error;
1346
    }
1347

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

    
1351
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1352
        c->http_error = 200;
1353
        q = c->buffer;
1354
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1355
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1356
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1357
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1358
        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");
1359
        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",
1360
            current_bandwidth, max_bandwidth);
1361
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1362

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

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

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

    
1382
            p++;
1383
        }
1384

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

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

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

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

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

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

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

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

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

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

    
1490
    stream->conns_served++;
1491

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

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

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

    
1514
                p++;
1515
            }
1516

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

    
1520
                logline += 17;
1521

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1690
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1691
                         sfilename, stream->filename);
1692
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1693
                        stream->conns_served);
1694
            fmt_bytecount(pb, stream->bytes_served);
1695
            switch(stream->stream_type) {
1696
            case STREAM_TYPE_LIVE: {
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
            stream_pos = parse_date(buf, 0);
1936
            if (stream_pos == INT64_MIN)
1937
                return -1;
1938
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1939
            int prebuffer = strtol(buf, 0, 10);
1940
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1941
        } else
1942
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1943
    } else {
1944
        strcpy(input_filename, c->stream->feed_filename);
1945
        buf_size = 0;
1946
        /* compute position (relative time) */
1947
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1948
            stream_pos = parse_date(buf, 1);
1949
            if (stream_pos == INT64_MIN)
1950
                return -1;
1951
        } else
1952
            stream_pos = 0;
1953
    }
1954
    if (input_filename[0] == '\0')
1955
        return -1;
1956

    
1957
#if 0
1958
    { time_t when = stream_pos / 1000000;
1959
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1960
    }
1961
#endif
1962

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

    
1973
    /* open each parser */
1974
    for(i=0;i<s->nb_streams;i++)
1975
        open_parser(s, i);
1976

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

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

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

    
2004
/* return the estimated time at which the current packet must be sent
2005
   (in us) */
2006
static int64_t get_packet_send_clock(HTTPContext *c)
2007
{
2008
    int bytes_left, bytes_sent, frame_bytes;
2009

    
2010
    frame_bytes = c->cur_frame_bytes;
2011
    if (frame_bytes <= 0)
2012
        return c->cur_pts;
2013
    else {
2014
        bytes_left = c->buffer_end - c->buffer_ptr;
2015
        bytes_sent = frame_bytes - bytes_left;
2016
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2017
    }
2018
}
2019

    
2020

    
2021
static int http_prepare_data(HTTPContext *c)
2022
{
2023
    int i, len, ret;
2024
    AVFormatContext *ctx;
2025

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

    
2039
        for(i=0;i<c->stream->nb_streams;i++) {
2040
            AVStream *st;
2041
            AVStream *src;
2042
            st = av_mallocz(sizeof(AVStream));
2043
            c->fmt_ctx.streams[i] = st;
2044
            /* if file or feed, then just take streams from FFStream struct */
2045
            if (!c->stream->feed ||
2046
                c->stream->feed == c->stream)
2047
                src = c->stream->streams[i];
2048
            else
2049
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2050

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

    
2060
        c->got_key_frame = 0;
2061

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

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

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

    
2083
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2084
        c->buffer_ptr = c->pb_buffer;
2085
        c->buffer_end = c->pb_buffer + len;
2086

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

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

    
2194
                    if (c->is_packetized) {
2195
                        int max_packet_size;
2196
                        if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2197
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2198
                        else
2199
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2200
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2201
                    } else {
2202
                        ret = url_open_dyn_buf(&ctx->pb);
2203
                    }
2204
                    if (ret < 0) {
2205
                        /* XXX: potential leak */
2206
                        return -1;
2207
                    }
2208
                    ost = ctx->streams[pkt.stream_index];
2209

    
2210
                    ctx->pb->is_streamed = 1;
2211
                    if (pkt.dts != AV_NOPTS_VALUE)
2212
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2213
                    if (pkt.pts != AV_NOPTS_VALUE)
2214
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2215
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2216
                    if (av_write_frame(ctx, &pkt) < 0) {
2217
                        http_log("Error writing frame to output\n");
2218
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2219
                    }
2220

    
2221
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2222
                    c->cur_frame_bytes = len;
2223
                    c->buffer_ptr = c->pb_buffer;
2224
                    c->buffer_end = c->pb_buffer + len;
2225

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

    
2253
        c->last_packet_sent = 1;
2254
        break;
2255
    }
2256
    return 0;
2257
}
2258

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

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

    
2295
                c->data_count += len;
2296
                update_datarate(&c->datarate, c->data_count);
2297
                if (c->stream)
2298
                    c->stream->bytes_served += len;
2299

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

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

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

    
2370
                c->data_count += len;
2371
                update_datarate(&c->datarate, c->data_count);
2372
                if (c->stream)
2373
                    c->stream->bytes_served += len;
2374
                break;
2375
            }
2376
        }
2377
    } /* for(;;) */
2378
    return 0;
2379
}
2380

    
2381
static int http_start_receive_data(HTTPContext *c)
2382
{
2383
    int fd;
2384

    
2385
    if (c->stream->feed_opened)
2386
        return -1;
2387

    
2388
    /* Don't permit writing to this one */
2389
    if (c->stream->readonly)
2390
        return -1;
2391

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

    
2400
    c->stream->feed_write_index = ffm_read_write_index(fd);
2401
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2402
    lseek(fd, 0, SEEK_SET);
2403

    
2404
    /* init buffer input */
2405
    c->buffer_ptr = c->buffer;
2406
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2407
    c->stream->feed_opened = 1;
2408
    return 0;
2409
}
2410

    
2411
static int http_receive_data(HTTPContext *c)
2412
{
2413
    HTTPContext *c1;
2414

    
2415
    if (c->buffer_end > c->buffer_ptr) {
2416
        int len;
2417

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

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

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

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

    
2456
            feed->feed_write_index += FFM_PACKET_SIZE;
2457
            /* update file size */
2458
            if (feed->feed_write_index > c->stream->feed_size)
2459
                feed->feed_size = feed->feed_write_index;
2460

    
2461
            /* handle wrap around if max file size reached */
2462
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2463
                feed->feed_write_index = FFM_PACKET_SIZE;
2464

    
2465
            /* write index */
2466
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2467

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

    
2481
            /* use feed output format name to find corresponding input format */
2482
            fmt_in = av_find_input_format(feed->fmt->name);
2483
            if (!fmt_in)
2484
                goto fail;
2485

    
2486
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2487
            pb->is_streamed = 1;
2488

    
2489
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2490
                av_free(pb);
2491
                goto fail;
2492
            }
2493

    
2494
            /* Now we have the actual streams */
2495
            if (s->nb_streams != feed->nb_streams) {
2496
                av_close_input_stream(s);
2497
                av_free(pb);
2498
                goto fail;
2499
            }
2500

    
2501
            for (i = 0; i < s->nb_streams; i++) {
2502
                AVStream *fst = feed->streams[i];
2503
                AVStream *st = s->streams[i];
2504
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2505
                if (fst->codec->extradata_size) {
2506
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2507
                    if (!fst->codec->extradata)
2508
                        goto fail;
2509
                    memcpy(fst->codec->extradata, st->codec->extradata,
2510
                           fst->codec->extradata_size);
2511
                }
2512
            }
2513

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

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

    
2533
/********************************************************************/
2534
/* RTSP handling */
2535

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2722
    return strlen(*pbuffer);
2723
}
2724

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2940

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

    
2944

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

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

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

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

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

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

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

    
3002
    rtp_c->state = HTTPSTATE_SEND_DATA;
3003

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

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

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

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

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

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

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

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

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

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

    
3059

    
3060
/********************************************************************/
3061
/* RTP handling */
3062

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

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

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

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

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

    
3112
    current_bandwidth += stream->bandwidth;
3113

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3222
/********************************************************************/
3223
/* ffserver initialization */
3224

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3545
        close(fd);
3546
    }
3547
}
3548

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

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

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

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

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

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

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

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

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

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

    
3666

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

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

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

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

    
3687
    return p->id;
3688
}
3689

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

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

    
3697
    return p->id;
3698
}
3699

    
3700
/* simplistic plugin support */
3701

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

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

    
3722
    init_func();
3723
}
3724
#endif
3725

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4430
    need_to_start_children = 1;
4431
}
4432

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

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

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

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

    
4463
    av_register_all();
4464

    
4465
    show_banner();
4466

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

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

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

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

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

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

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

    
4489
    build_file_streams();
4490

    
4491
    build_feed_streams();
4492

    
4493
    compute_bandwidth();
4494

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

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

    
4520
    /* signal init */
4521
    signal(SIGPIPE, SIG_IGN);
4522

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

    
4532
    if (ffserver_daemon)
4533
        chdir("/");
4534

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

    
4540
    return 0;
4541
}