Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 042819c5

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
#define _XOPEN_SOURCE 600
23

    
24
#include "config.h"
25
#if !HAVE_CLOSESOCKET
26
#define closesocket close
27
#endif
28
#include <string.h>
29
#include <strings.h>
30
#include <stdlib.h>
31
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35
#include "libavformat/rtpdec.h"
36
#include "libavformat/rtsp.h"
37
#include "libavutil/avstring.h"
38
#include "libavutil/lfg.h"
39
#include "libavutil/random_seed.h"
40
#include "libavutil/intreadwrite.h"
41
#include "libavcodec/opt.h"
42
#include <stdarg.h>
43
#include <unistd.h>
44
#include <fcntl.h>
45
#include <sys/ioctl.h>
46
#if HAVE_POLL_H
47
#include <poll.h>
48
#endif
49
#include <errno.h>
50
#include <sys/time.h>
51
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
52
#include <time.h>
53
#include <sys/wait.h>
54
#include <signal.h>
55
#if HAVE_DLFCN_H
56
#include <dlfcn.h>
57
#endif
58

    
59
#include "cmdutils.h"
60

    
61
#undef exit
62

    
63
const char program_name[] = "FFserver";
64
const int program_birth_year = 2000;
65

    
66
static const OptionDef options[];
67

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

    
78
    RTSPSTATE_WAIT_REQUEST,
79
    RTSPSTATE_SEND_REPLY,
80
    RTSPSTATE_SEND_PACKET,
81
};
82

    
83
static const char *http_state[] = {
84
    "HTTP_WAIT_REQUEST",
85
    "HTTP_SEND_HEADER",
86

    
87
    "SEND_DATA_HEADER",
88
    "SEND_DATA",
89
    "SEND_DATA_TRAILER",
90
    "RECEIVE_DATA",
91
    "WAIT_FEED",
92
    "READY",
93

    
94
    "RTSP_WAIT_REQUEST",
95
    "RTSP_SEND_REPLY",
96
    "RTSP_SEND_PACKET",
97
};
98

    
99
#define IOBUFFER_INIT_SIZE 8192
100

    
101
/* timeouts are in ms */
102
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

    
107
typedef struct RTSPActionServerSetup {
108
    uint32_t ipaddr;
109
    char transport_option[512];
110
} RTSPActionServerSetup;
111

    
112
typedef struct {
113
    int64_t count1, count2;
114
    int64_t time1, time2;
115
} DataRateData;
116

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

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

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

    
172
    /* RTP/UDP specific */
173
    URLContext *rtp_handles[MAX_STREAMS];
174

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

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

    
187
enum IPAddressAction {
188
    IP_ALLOW = 1,
189
    IP_DENY,
190
};
191

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

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

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

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

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

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

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

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

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

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

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

    
398

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

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

    
408
            feed->pid = fork();
409

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

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

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

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

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

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

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

    
451
                signal(SIGPIPE, SIG_DFL);
452

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

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

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

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

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

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

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

    
490
    return server_fd;
491
}
492

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
580
    start_children(first_feed);
581

    
582
    start_multicast();
583

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

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

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

    
656
        cur_time = av_gettime() / 1000;
657

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

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

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

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

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

    
703
static void new_connection(int server_fd, int is_rtsp)
704
{
705
    struct sockaddr_in from_addr;
706
    int fd, len;
707
    HTTPContext *c = NULL;
708

    
709
    len = sizeof(from_addr);
710
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
711
                &len);
712
    if (fd < 0) {
713
        http_log("error during accept %s\n", strerror(errno));
714
        return;
715
    }
716
    ff_socket_nonblock(fd, 1);
717

    
718
    /* XXX: should output a warning page when coming
719
       close to the connection limit */
720
    if (nb_connections >= nb_max_connections)
721
        goto fail;
722

    
723
    /* add a new connection */
724
    c = av_mallocz(sizeof(HTTPContext));
725
    if (!c)
726
        goto fail;
727

    
728
    c->fd = fd;
729
    c->poll_entry = NULL;
730
    c->from_addr = from_addr;
731
    c->buffer_size = IOBUFFER_INIT_SIZE;
732
    c->buffer = av_malloc(c->buffer_size);
733
    if (!c->buffer)
734
        goto fail;
735

    
736
    c->next = first_http_ctx;
737
    first_http_ctx = c;
738
    nb_connections++;
739

    
740
    start_wait_request(c, is_rtsp);
741

    
742
    return;
743

    
744
 fail:
745
    if (c) {
746
        av_free(c->buffer);
747
        av_free(c);
748
    }
749
    closesocket(fd);
750
}
751

    
752
static void close_connection(HTTPContext *c)
753
{
754
    HTTPContext **cp, *c1;
755
    int i, nb_streams;
756
    AVFormatContext *ctx;
757
    URLContext *h;
758
    AVStream *st;
759

    
760
    /* remove connection from list */
761
    cp = &first_http_ctx;
762
    while ((*cp) != NULL) {
763
        c1 = *cp;
764
        if (c1 == c)
765
            *cp = c->next;
766
        else
767
            cp = &c1->next;
768
    }
769

    
770
    /* remove references, if any (XXX: do it faster) */
771
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
772
        if (c1->rtsp_c == c)
773
            c1->rtsp_c = NULL;
774
    }
775

    
776
    /* remove connection associated resources */
777
    if (c->fd >= 0)
778
        closesocket(c->fd);
779
    if (c->fmt_in) {
780
        /* close each frame parser */
781
        for(i=0;i<c->fmt_in->nb_streams;i++) {
782
            st = c->fmt_in->streams[i];
783
            if (st->codec->codec)
784
                avcodec_close(st->codec);
785
        }
786
        av_close_input_file(c->fmt_in);
787
    }
788

    
789
    /* free RTP output streams if any */
790
    nb_streams = 0;
791
    if (c->stream)
792
        nb_streams = c->stream->nb_streams;
793

    
794
    for(i=0;i<nb_streams;i++) {
795
        ctx = c->rtp_ctx[i];
796
        if (ctx) {
797
            av_write_trailer(ctx);
798
            av_free(ctx);
799
        }
800
        h = c->rtp_handles[i];
801
        if (h)
802
            url_close(h);
803
    }
804

    
805
    ctx = &c->fmt_ctx;
806

    
807
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
808
        if (ctx->oformat) {
809
            /* prepare header */
810
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
811
                av_write_trailer(ctx);
812
                av_freep(&c->pb_buffer);
813
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
814
            }
815
        }
816
    }
817

    
818
    for(i=0; i<ctx->nb_streams; i++)
819
        av_free(ctx->streams[i]);
820

    
821
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
822
        current_bandwidth -= c->stream->bandwidth;
823

    
824
    /* signal that there is no feed if we are the feeder socket */
825
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
826
        c->stream->feed_opened = 0;
827
        close(c->feed_fd);
828
    }
829

    
830
    av_freep(&c->pb_buffer);
831
    av_freep(&c->packet_buffer);
832
    av_free(c->buffer);
833
    av_free(c);
834
    nb_connections--;
835
}
836

    
837
static int handle_connection(HTTPContext *c)
838
{
839
    int len, ret;
840

    
841
    switch(c->state) {
842
    case HTTPSTATE_WAIT_REQUEST:
843
    case RTSPSTATE_WAIT_REQUEST:
844
        /* timeout ? */
845
        if ((c->timeout - cur_time) < 0)
846
            return -1;
847
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
848
            return -1;
849

    
850
        /* no need to read if no events */
851
        if (!(c->poll_entry->revents & POLLIN))
852
            return 0;
853
        /* read the data */
854
    read_loop:
855
        len = recv(c->fd, c->buffer_ptr, 1, 0);
856
        if (len < 0) {
857
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
858
                ff_neterrno() != FF_NETERROR(EINTR))
859
                return -1;
860
        } else if (len == 0) {
861
            return -1;
862
        } else {
863
            /* search for end of request. */
864
            uint8_t *ptr;
865
            c->buffer_ptr += len;
866
            ptr = c->buffer_ptr;
867
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
868
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
869
                /* request found : parse it and reply */
870
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
871
                    ret = http_parse_request(c);
872
                } else {
873
                    ret = rtsp_parse_request(c);
874
                }
875
                if (ret < 0)
876
                    return -1;
877
            } else if (ptr >= c->buffer_end) {
878
                /* request too long: cannot do anything */
879
                return -1;
880
            } else goto read_loop;
881
        }
882
        break;
883

    
884
    case HTTPSTATE_SEND_HEADER:
885
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
886
            return -1;
887

    
888
        /* no need to write if no events */
889
        if (!(c->poll_entry->revents & POLLOUT))
890
            return 0;
891
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
892
        if (len < 0) {
893
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
894
                ff_neterrno() != FF_NETERROR(EINTR)) {
895
                /* error : close connection */
896
                av_freep(&c->pb_buffer);
897
                return -1;
898
            }
899
        } else {
900
            c->buffer_ptr += len;
901
            if (c->stream)
902
                c->stream->bytes_served += len;
903
            c->data_count += len;
904
            if (c->buffer_ptr >= c->buffer_end) {
905
                av_freep(&c->pb_buffer);
906
                /* if error, exit */
907
                if (c->http_error)
908
                    return -1;
909
                /* all the buffer was sent : synchronize to the incoming stream */
910
                c->state = HTTPSTATE_SEND_DATA_HEADER;
911
                c->buffer_ptr = c->buffer_end = c->buffer;
912
            }
913
        }
914
        break;
915

    
916
    case HTTPSTATE_SEND_DATA:
917
    case HTTPSTATE_SEND_DATA_HEADER:
918
    case HTTPSTATE_SEND_DATA_TRAILER:
919
        /* for packetized output, we consider we can always write (the
920
           input streams sets the speed). It may be better to verify
921
           that we do not rely too much on the kernel queues */
922
        if (!c->is_packetized) {
923
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
924
                return -1;
925

    
926
            /* no need to read if no events */
927
            if (!(c->poll_entry->revents & POLLOUT))
928
                return 0;
929
        }
930
        if (http_send_data(c) < 0)
931
            return -1;
932
        /* close connection if trailer sent */
933
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
934
            return -1;
935
        break;
936
    case HTTPSTATE_RECEIVE_DATA:
937
        /* no need to read if no events */
938
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
939
            return -1;
940
        if (!(c->poll_entry->revents & POLLIN))
941
            return 0;
942
        if (http_receive_data(c) < 0)
943
            return -1;
944
        break;
945
    case HTTPSTATE_WAIT_FEED:
946
        /* no need to read if no events */
947
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
948
            return -1;
949

    
950
        /* nothing to do, we'll be waken up by incoming feed packets */
951
        break;
952

    
953
    case RTSPSTATE_SEND_REPLY:
954
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
955
            av_freep(&c->pb_buffer);
956
            return -1;
957
        }
958
        /* no need to write if no events */
959
        if (!(c->poll_entry->revents & POLLOUT))
960
            return 0;
961
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
962
        if (len < 0) {
963
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
964
                ff_neterrno() != FF_NETERROR(EINTR)) {
965
                /* error : close connection */
966
                av_freep(&c->pb_buffer);
967
                return -1;
968
            }
969
        } else {
970
            c->buffer_ptr += len;
971
            c->data_count += len;
972
            if (c->buffer_ptr >= c->buffer_end) {
973
                /* all the buffer was sent : wait for a new request */
974
                av_freep(&c->pb_buffer);
975
                start_wait_request(c, 1);
976
            }
977
        }
978
        break;
979
    case RTSPSTATE_SEND_PACKET:
980
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
981
            av_freep(&c->packet_buffer);
982
            return -1;
983
        }
984
        /* no need to write if no events */
985
        if (!(c->poll_entry->revents & POLLOUT))
986
            return 0;
987
        len = send(c->fd, c->packet_buffer_ptr,
988
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
989
        if (len < 0) {
990
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
991
                ff_neterrno() != FF_NETERROR(EINTR)) {
992
                /* error : close connection */
993
                av_freep(&c->packet_buffer);
994
                return -1;
995
            }
996
        } else {
997
            c->packet_buffer_ptr += len;
998
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
999
                /* all the buffer was sent : wait for a new request */
1000
                av_freep(&c->packet_buffer);
1001
                c->state = RTSPSTATE_WAIT_REQUEST;
1002
            }
1003
        }
1004
        break;
1005
    case HTTPSTATE_READY:
1006
        /* nothing to do */
1007
        break;
1008
    default:
1009
        return -1;
1010
    }
1011
    return 0;
1012
}
1013

    
1014
static int extract_rates(char *rates, int ratelen, const char *request)
1015
{
1016
    const char *p;
1017

    
1018
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1019
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1020
            const char *q = p + 7;
1021

    
1022
            while (*q && *q != '\n' && isspace(*q))
1023
                q++;
1024

    
1025
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1026
                int stream_no;
1027
                int rate_no;
1028

    
1029
                q += 20;
1030

    
1031
                memset(rates, 0xff, ratelen);
1032

    
1033
                while (1) {
1034
                    while (*q && *q != '\n' && *q != ':')
1035
                        q++;
1036

    
1037
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1038
                        break;
1039

    
1040
                    stream_no--;
1041
                    if (stream_no < ratelen && stream_no >= 0)
1042
                        rates[stream_no] = rate_no;
1043

    
1044
                    while (*q && *q != '\n' && !isspace(*q))
1045
                        q++;
1046
                }
1047

    
1048
                return 1;
1049
            }
1050
        }
1051
        p = strchr(p, '\n');
1052
        if (!p)
1053
            break;
1054

    
1055
        p++;
1056
    }
1057

    
1058
    return 0;
1059
}
1060

    
1061
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1062
{
1063
    int i;
1064
    int best_bitrate = 100000000;
1065
    int best = -1;
1066

    
1067
    for (i = 0; i < feed->nb_streams; i++) {
1068
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1069

    
1070
        if (feed_codec->codec_id != codec->codec_id ||
1071
            feed_codec->sample_rate != codec->sample_rate ||
1072
            feed_codec->width != codec->width ||
1073
            feed_codec->height != codec->height)
1074
            continue;
1075

    
1076
        /* Potential stream */
1077

    
1078
        /* We want the fastest stream less than bit_rate, or the slowest
1079
         * faster than bit_rate
1080
         */
1081

    
1082
        if (feed_codec->bit_rate <= bit_rate) {
1083
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1084
                best_bitrate = feed_codec->bit_rate;
1085
                best = i;
1086
            }
1087
        } else {
1088
            if (feed_codec->bit_rate < best_bitrate) {
1089
                best_bitrate = feed_codec->bit_rate;
1090
                best = i;
1091
            }
1092
        }
1093
    }
1094

    
1095
    return best;
1096
}
1097

    
1098
static int modify_current_stream(HTTPContext *c, char *rates)
1099
{
1100
    int i;
1101
    FFStream *req = c->stream;
1102
    int action_required = 0;
1103

    
1104
    /* Not much we can do for a feed */
1105
    if (!req->feed)
1106
        return 0;
1107

    
1108
    for (i = 0; i < req->nb_streams; i++) {
1109
        AVCodecContext *codec = req->streams[i]->codec;
1110

    
1111
        switch(rates[i]) {
1112
            case 0:
1113
                c->switch_feed_streams[i] = req->feed_streams[i];
1114
                break;
1115
            case 1:
1116
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1117
                break;
1118
            case 2:
1119
                /* Wants off or slow */
1120
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1121
#ifdef WANTS_OFF
1122
                /* This doesn't work well when it turns off the only stream! */
1123
                c->switch_feed_streams[i] = -2;
1124
                c->feed_streams[i] = -2;
1125
#endif
1126
                break;
1127
        }
1128

    
1129
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1130
            action_required = 1;
1131
    }
1132

    
1133
    return action_required;
1134
}
1135

    
1136

    
1137
static void do_switch_stream(HTTPContext *c, int i)
1138
{
1139
    if (c->switch_feed_streams[i] >= 0) {
1140
#ifdef PHILIP
1141
        c->feed_streams[i] = c->switch_feed_streams[i];
1142
#endif
1143

    
1144
        /* Now update the stream */
1145
    }
1146
    c->switch_feed_streams[i] = -1;
1147
}
1148

    
1149
/* XXX: factorize in utils.c ? */
1150
/* XXX: take care with different space meaning */
1151
static void skip_spaces(const char **pp)
1152
{
1153
    const char *p;
1154
    p = *pp;
1155
    while (*p == ' ' || *p == '\t')
1156
        p++;
1157
    *pp = p;
1158
}
1159

    
1160
static void get_word(char *buf, int buf_size, const char **pp)
1161
{
1162
    const char *p;
1163
    char *q;
1164

    
1165
    p = *pp;
1166
    skip_spaces(&p);
1167
    q = buf;
1168
    while (!isspace(*p) && *p != '\0') {
1169
        if ((q - buf) < buf_size - 1)
1170
            *q++ = *p;
1171
        p++;
1172
    }
1173
    if (buf_size > 0)
1174
        *q = '\0';
1175
    *pp = p;
1176
}
1177

    
1178
static int validate_acl(FFStream *stream, HTTPContext *c)
1179
{
1180
    enum IPAddressAction last_action = IP_DENY;
1181
    IPAddressACL *acl;
1182
    struct in_addr *src = &c->from_addr.sin_addr;
1183
    unsigned long src_addr = src->s_addr;
1184

    
1185
    for (acl = stream->acl; acl; acl = acl->next) {
1186
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1187
            return (acl->action == IP_ALLOW) ? 1 : 0;
1188
        last_action = acl->action;
1189
    }
1190

    
1191
    /* Nothing matched, so return not the last action */
1192
    return (last_action == IP_DENY) ? 1 : 0;
1193
}
1194

    
1195
/* compute the real filename of a file by matching it without its
1196
   extensions to all the stream filenames */
1197
static void compute_real_filename(char *filename, int max_size)
1198
{
1199
    char file1[1024];
1200
    char file2[1024];
1201
    char *p;
1202
    FFStream *stream;
1203

    
1204
    /* compute filename by matching without the file extensions */
1205
    av_strlcpy(file1, filename, sizeof(file1));
1206
    p = strrchr(file1, '.');
1207
    if (p)
1208
        *p = '\0';
1209
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1210
        av_strlcpy(file2, stream->filename, sizeof(file2));
1211
        p = strrchr(file2, '.');
1212
        if (p)
1213
            *p = '\0';
1214
        if (!strcmp(file1, file2)) {
1215
            av_strlcpy(filename, stream->filename, max_size);
1216
            break;
1217
        }
1218
    }
1219
}
1220

    
1221
enum RedirType {
1222
    REDIR_NONE,
1223
    REDIR_ASX,
1224
    REDIR_RAM,
1225
    REDIR_ASF,
1226
    REDIR_RTSP,
1227
    REDIR_SDP,
1228
};
1229

    
1230
/* parse http request and prepare header */
1231
static int http_parse_request(HTTPContext *c)
1232
{
1233
    char *p;
1234
    enum RedirType redir_type;
1235
    char cmd[32];
1236
    char info[1024], filename[1024];
1237
    char url[1024], *q;
1238
    char protocol[32];
1239
    char msg[1024];
1240
    const char *mime_type;
1241
    FFStream *stream;
1242
    int i;
1243
    char ratebuf[32];
1244
    char *useragent = 0;
1245

    
1246
    p = c->buffer;
1247
    get_word(cmd, sizeof(cmd), (const char **)&p);
1248
    av_strlcpy(c->method, cmd, sizeof(c->method));
1249

    
1250
    if (!strcmp(cmd, "GET"))
1251
        c->post = 0;
1252
    else if (!strcmp(cmd, "POST"))
1253
        c->post = 1;
1254
    else
1255
        return -1;
1256

    
1257
    get_word(url, sizeof(url), (const char **)&p);
1258
    av_strlcpy(c->url, url, sizeof(c->url));
1259

    
1260
    get_word(protocol, sizeof(protocol), (const char **)&p);
1261
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1262
        return -1;
1263

    
1264
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1265

    
1266
    if (ffserver_debug)
1267
        http_log("New connection: %s %s\n", cmd, url);
1268

    
1269
    /* find the filename and the optional info string in the request */
1270
    p = strchr(url, '?');
1271
    if (p) {
1272
        av_strlcpy(info, p, sizeof(info));
1273
        *p = '\0';
1274
    } else
1275
        info[0] = '\0';
1276

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

    
1279
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1280
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1281
            useragent = p + 11;
1282
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1283
                useragent++;
1284
            break;
1285
        }
1286
        p = strchr(p, '\n');
1287
        if (!p)
1288
            break;
1289

    
1290
        p++;
1291
    }
1292

    
1293
    redir_type = REDIR_NONE;
1294
    if (match_ext(filename, "asx")) {
1295
        redir_type = REDIR_ASX;
1296
        filename[strlen(filename)-1] = 'f';
1297
    } else if (match_ext(filename, "asf") &&
1298
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1299
        /* if this isn't WMP or lookalike, return the redirector file */
1300
        redir_type = REDIR_ASF;
1301
    } else if (match_ext(filename, "rpm,ram")) {
1302
        redir_type = REDIR_RAM;
1303
        strcpy(filename + strlen(filename)-2, "m");
1304
    } else if (match_ext(filename, "rtsp")) {
1305
        redir_type = REDIR_RTSP;
1306
        compute_real_filename(filename, sizeof(filename) - 1);
1307
    } else if (match_ext(filename, "sdp")) {
1308
        redir_type = REDIR_SDP;
1309
        compute_real_filename(filename, sizeof(filename) - 1);
1310
    }
1311

    
1312
    // "redirect" / request to index.html
1313
    if (!strlen(filename))
1314
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1315

    
1316
    stream = first_stream;
1317
    while (stream != NULL) {
1318
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1319
            break;
1320
        stream = stream->next;
1321
    }
1322
    if (stream == NULL) {
1323
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1324
        goto send_error;
1325
    }
1326

    
1327
    c->stream = stream;
1328
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1329
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1330

    
1331
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1332
        c->http_error = 301;
1333
        q = c->buffer;
1334
        q += snprintf(q, c->buffer_size,
1335
                      "HTTP/1.0 301 Moved\r\n"
1336
                      "Location: %s\r\n"
1337
                      "Content-type: text/html\r\n"
1338
                      "\r\n"
1339
                      "<html><head><title>Moved</title></head><body>\r\n"
1340
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1341
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1342
        /* prepare output buffer */
1343
        c->buffer_ptr = c->buffer;
1344
        c->buffer_end = q;
1345
        c->state = HTTPSTATE_SEND_HEADER;
1346
        return 0;
1347
    }
1348

    
1349
    /* If this is WMP, get the rate information */
1350
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1351
        if (modify_current_stream(c, ratebuf)) {
1352
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1353
                if (c->switch_feed_streams[i] >= 0)
1354
                    do_switch_stream(c, i);
1355
            }
1356
        }
1357
    }
1358

    
1359
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1360
        current_bandwidth += stream->bandwidth;
1361

    
1362
    /* If already streaming this feed, do not let start another feeder. */
1363
    if (stream->feed_opened) {
1364
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1365
        http_log("feed %s already being received\n", stream->feed_filename);
1366
        goto send_error;
1367
    }
1368

    
1369
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1370
        c->http_error = 200;
1371
        q = c->buffer;
1372
        q += snprintf(q, c->buffer_size,
1373
                      "HTTP/1.0 200 Server too busy\r\n"
1374
                      "Content-type: text/html\r\n"
1375
                      "\r\n"
1376
                      "<html><head><title>Too busy</title></head><body>\r\n"
1377
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1378
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1379
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1380
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1381
        /* prepare output buffer */
1382
        c->buffer_ptr = c->buffer;
1383
        c->buffer_end = q;
1384
        c->state = HTTPSTATE_SEND_HEADER;
1385
        return 0;
1386
    }
1387

    
1388
    if (redir_type != REDIR_NONE) {
1389
        char *hostinfo = 0;
1390

    
1391
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1392
            if (strncasecmp(p, "Host:", 5) == 0) {
1393
                hostinfo = p + 5;
1394
                break;
1395
            }
1396
            p = strchr(p, '\n');
1397
            if (!p)
1398
                break;
1399

    
1400
            p++;
1401
        }
1402

    
1403
        if (hostinfo) {
1404
            char *eoh;
1405
            char hostbuf[260];
1406

    
1407
            while (isspace(*hostinfo))
1408
                hostinfo++;
1409

    
1410
            eoh = strchr(hostinfo, '\n');
1411
            if (eoh) {
1412
                if (eoh[-1] == '\r')
1413
                    eoh--;
1414

    
1415
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1416
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1417
                    hostbuf[eoh - hostinfo] = 0;
1418

    
1419
                    c->http_error = 200;
1420
                    q = c->buffer;
1421
                    switch(redir_type) {
1422
                    case REDIR_ASX:
1423
                        q += snprintf(q, c->buffer_size,
1424
                                      "HTTP/1.0 200 ASX Follows\r\n"
1425
                                      "Content-type: video/x-ms-asf\r\n"
1426
                                      "\r\n"
1427
                                      "<ASX Version=\"3\">\r\n"
1428
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1429
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1430
                                      "</ASX>\r\n", hostbuf, filename, info);
1431
                        break;
1432
                    case REDIR_RAM:
1433
                        q += snprintf(q, c->buffer_size,
1434
                                      "HTTP/1.0 200 RAM Follows\r\n"
1435
                                      "Content-type: audio/x-pn-realaudio\r\n"
1436
                                      "\r\n"
1437
                                      "# Autogenerated by ffserver\r\n"
1438
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1439
                        break;
1440
                    case REDIR_ASF:
1441
                        q += snprintf(q, c->buffer_size,
1442
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1443
                                      "Content-type: video/x-ms-asf\r\n"
1444
                                      "\r\n"
1445
                                      "[Reference]\r\n"
1446
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1447
                        break;
1448
                    case REDIR_RTSP:
1449
                        {
1450
                            char hostname[256], *p;
1451
                            /* extract only hostname */
1452
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1453
                            p = strrchr(hostname, ':');
1454
                            if (p)
1455
                                *p = '\0';
1456
                            q += snprintf(q, c->buffer_size,
1457
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1458
                                          /* XXX: incorrect mime type ? */
1459
                                          "Content-type: application/x-rtsp\r\n"
1460
                                          "\r\n"
1461
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1462
                        }
1463
                        break;
1464
                    case REDIR_SDP:
1465
                        {
1466
                            uint8_t *sdp_data;
1467
                            int sdp_data_size, len;
1468
                            struct sockaddr_in my_addr;
1469

    
1470
                            q += snprintf(q, c->buffer_size,
1471
                                          "HTTP/1.0 200 OK\r\n"
1472
                                          "Content-type: application/sdp\r\n"
1473
                                          "\r\n");
1474

    
1475
                            len = sizeof(my_addr);
1476
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1477

    
1478
                            /* XXX: should use a dynamic buffer */
1479
                            sdp_data_size = prepare_sdp_description(stream,
1480
                                                                    &sdp_data,
1481
                                                                    my_addr.sin_addr);
1482
                            if (sdp_data_size > 0) {
1483
                                memcpy(q, sdp_data, sdp_data_size);
1484
                                q += sdp_data_size;
1485
                                *q = '\0';
1486
                                av_free(sdp_data);
1487
                            }
1488
                        }
1489
                        break;
1490
                    default:
1491
                        abort();
1492
                        break;
1493
                    }
1494

    
1495
                    /* prepare output buffer */
1496
                    c->buffer_ptr = c->buffer;
1497
                    c->buffer_end = q;
1498
                    c->state = HTTPSTATE_SEND_HEADER;
1499
                    return 0;
1500
                }
1501
            }
1502
        }
1503

    
1504
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1505
        goto send_error;
1506
    }
1507

    
1508
    stream->conns_served++;
1509

    
1510
    /* XXX: add there authenticate and IP match */
1511

    
1512
    if (c->post) {
1513
        /* if post, it means a feed is being sent */
1514
        if (!stream->is_feed) {
1515
            /* However it might be a status report from WMP! Let us log the
1516
             * data as it might come in handy one day. */
1517
            char *logline = 0;
1518
            int client_id = 0;
1519

    
1520
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1521
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1522
                    logline = p;
1523
                    break;
1524
                }
1525
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1526
                    client_id = strtol(p + 18, 0, 10);
1527
                p = strchr(p, '\n');
1528
                if (!p)
1529
                    break;
1530

    
1531
                p++;
1532
            }
1533

    
1534
            if (logline) {
1535
                char *eol = strchr(logline, '\n');
1536

    
1537
                logline += 17;
1538

    
1539
                if (eol) {
1540
                    if (eol[-1] == '\r')
1541
                        eol--;
1542
                    http_log("%.*s\n", (int) (eol - logline), logline);
1543
                    c->suppress_log = 1;
1544
                }
1545
            }
1546

    
1547
#ifdef DEBUG_WMP
1548
            http_log("\nGot request:\n%s\n", c->buffer);
1549
#endif
1550

    
1551
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1552
                HTTPContext *wmpc;
1553

    
1554
                /* Now we have to find the client_id */
1555
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1556
                    if (wmpc->wmp_client_id == client_id)
1557
                        break;
1558
                }
1559

    
1560
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1561
                    wmpc->switch_pending = 1;
1562
            }
1563

    
1564
            snprintf(msg, sizeof(msg), "POST command not handled");
1565
            c->stream = 0;
1566
            goto send_error;
1567
        }
1568
        if (http_start_receive_data(c) < 0) {
1569
            snprintf(msg, sizeof(msg), "could not open feed");
1570
            goto send_error;
1571
        }
1572
        c->http_error = 0;
1573
        c->state = HTTPSTATE_RECEIVE_DATA;
1574
        return 0;
1575
    }
1576

    
1577
#ifdef DEBUG_WMP
1578
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1579
        http_log("\nGot request:\n%s\n", c->buffer);
1580
#endif
1581

    
1582
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1583
        goto send_status;
1584

    
1585
    /* open input stream */
1586
    if (open_input_stream(c, info) < 0) {
1587
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1588
        goto send_error;
1589
    }
1590

    
1591
    /* prepare http header */
1592
    q = c->buffer;
1593
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1594
    mime_type = c->stream->fmt->mime_type;
1595
    if (!mime_type)
1596
        mime_type = "application/x-octet-stream";
1597
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1598

    
1599
    /* for asf, we need extra headers */
1600
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1601
        /* Need to allocate a client id */
1602

    
1603
        c->wmp_client_id = av_lfg_get(&random_state);
1604

    
1605
        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);
1606
    }
1607
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1608
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1609

    
1610
    /* prepare output buffer */
1611
    c->http_error = 0;
1612
    c->buffer_ptr = c->buffer;
1613
    c->buffer_end = q;
1614
    c->state = HTTPSTATE_SEND_HEADER;
1615
    return 0;
1616
 send_error:
1617
    c->http_error = 404;
1618
    q = c->buffer;
1619
    q += snprintf(q, c->buffer_size,
1620
                  "HTTP/1.0 404 Not Found\r\n"
1621
                  "Content-type: text/html\r\n"
1622
                  "\r\n"
1623
                  "<HTML>\n"
1624
                  "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
1625
                  "<BODY>%s</BODY>\n"
1626
                  "</HTML>\n", msg);
1627
    /* prepare output buffer */
1628
    c->buffer_ptr = c->buffer;
1629
    c->buffer_end = q;
1630
    c->state = HTTPSTATE_SEND_HEADER;
1631
    return 0;
1632
 send_status:
1633
    compute_status(c);
1634
    c->http_error = 200; /* horrible : we use this value to avoid
1635
                            going to the send data state */
1636
    c->state = HTTPSTATE_SEND_HEADER;
1637
    return 0;
1638
}
1639

    
1640
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1641
{
1642
    static const char *suffix = " kMGTP";
1643
    const char *s;
1644

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

    
1647
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1648
}
1649

    
1650
static void compute_status(HTTPContext *c)
1651
{
1652
    HTTPContext *c1;
1653
    FFStream *stream;
1654
    char *p;
1655
    time_t ti;
1656
    int i, len;
1657
    ByteIOContext *pb;
1658

    
1659
    if (url_open_dyn_buf(&pb) < 0) {
1660
        /* XXX: return an error ? */
1661
        c->buffer_ptr = c->buffer;
1662
        c->buffer_end = c->buffer;
1663
        return;
1664
    }
1665

    
1666
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1667
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1668
    url_fprintf(pb, "Pragma: no-cache\r\n");
1669
    url_fprintf(pb, "\r\n");
1670

    
1671
    url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
1672
    if (c->stream->feed_filename[0])
1673
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1674
    url_fprintf(pb, "</HEAD>\n<BODY>");
1675
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1676
    /* format status */
1677
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1678
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1679
    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");
1680
    stream = first_stream;
1681
    while (stream != NULL) {
1682
        char sfilename[1024];
1683
        char *eosf;
1684

    
1685
        if (stream->feed != stream) {
1686
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1687
            eosf = sfilename + strlen(sfilename);
1688
            if (eosf - sfilename >= 4) {
1689
                if (strcmp(eosf - 4, ".asf") == 0)
1690
                    strcpy(eosf - 4, ".asx");
1691
                else if (strcmp(eosf - 3, ".rm") == 0)
1692
                    strcpy(eosf - 3, ".ram");
1693
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1694
                    /* generate a sample RTSP director if
1695
                       unicast. Generate an SDP redirector if
1696
                       multicast */
1697
                    eosf = strrchr(sfilename, '.');
1698
                    if (!eosf)
1699
                        eosf = sfilename + strlen(sfilename);
1700
                    if (stream->is_multicast)
1701
                        strcpy(eosf, ".sdp");
1702
                    else
1703
                        strcpy(eosf, ".rtsp");
1704
                }
1705
            }
1706

    
1707
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1708
                         sfilename, stream->filename);
1709
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1710
                        stream->conns_served);
1711
            fmt_bytecount(pb, stream->bytes_served);
1712
            switch(stream->stream_type) {
1713
            case STREAM_TYPE_LIVE: {
1714
                    int audio_bit_rate = 0;
1715
                    int video_bit_rate = 0;
1716
                    const char *audio_codec_name = "";
1717
                    const char *video_codec_name = "";
1718
                    const char *audio_codec_name_extra = "";
1719
                    const char *video_codec_name_extra = "";
1720

    
1721
                    for(i=0;i<stream->nb_streams;i++) {
1722
                        AVStream *st = stream->streams[i];
1723
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1724
                        switch(st->codec->codec_type) {
1725
                        case CODEC_TYPE_AUDIO:
1726
                            audio_bit_rate += st->codec->bit_rate;
1727
                            if (codec) {
1728
                                if (*audio_codec_name)
1729
                                    audio_codec_name_extra = "...";
1730
                                audio_codec_name = codec->name;
1731
                            }
1732
                            break;
1733
                        case CODEC_TYPE_VIDEO:
1734
                            video_bit_rate += st->codec->bit_rate;
1735
                            if (codec) {
1736
                                if (*video_codec_name)
1737
                                    video_codec_name_extra = "...";
1738
                                video_codec_name = codec->name;
1739
                            }
1740
                            break;
1741
                        case CODEC_TYPE_DATA:
1742
                            video_bit_rate += st->codec->bit_rate;
1743
                            break;
1744
                        default:
1745
                            abort();
1746
                        }
1747
                    }
1748
                    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",
1749
                                 stream->fmt->name,
1750
                                 stream->bandwidth,
1751
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1752
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1753
                    if (stream->feed)
1754
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1755
                    else
1756
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1757
                    url_fprintf(pb, "\n");
1758
                }
1759
                break;
1760
            default:
1761
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1762
                break;
1763
            }
1764
        }
1765
        stream = stream->next;
1766
    }
1767
    url_fprintf(pb, "</TABLE>\n");
1768

    
1769
    stream = first_stream;
1770
    while (stream != NULL) {
1771
        if (stream->feed == stream) {
1772
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1773
            if (stream->pid) {
1774
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1775

    
1776
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1777
                {
1778
                    FILE *pid_stat;
1779
                    char ps_cmd[64];
1780

    
1781
                    /* This is somewhat linux specific I guess */
1782
                    snprintf(ps_cmd, sizeof(ps_cmd),
1783
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1784
                             stream->pid);
1785

    
1786
                    pid_stat = popen(ps_cmd, "r");
1787
                    if (pid_stat) {
1788
                        char cpuperc[10];
1789
                        char cpuused[64];
1790

    
1791
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1792
                                   cpuused) == 2) {
1793
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1794
                                         cpuperc, cpuused);
1795
                        }
1796
                        fclose(pid_stat);
1797
                    }
1798
                }
1799
#endif
1800

    
1801
                url_fprintf(pb, "<p>");
1802
            }
1803
            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");
1804

    
1805
            for (i = 0; i < stream->nb_streams; i++) {
1806
                AVStream *st = stream->streams[i];
1807
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1808
                const char *type = "unknown";
1809
                char parameters[64];
1810

    
1811
                parameters[0] = 0;
1812

    
1813
                switch(st->codec->codec_type) {
1814
                case CODEC_TYPE_AUDIO:
1815
                    type = "audio";
1816
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1817
                    break;
1818
                case CODEC_TYPE_VIDEO:
1819
                    type = "video";
1820
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1821
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1822
                    break;
1823
                default:
1824
                    abort();
1825
                }
1826
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1827
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1828
            }
1829
            url_fprintf(pb, "</table>\n");
1830

    
1831
        }
1832
        stream = stream->next;
1833
    }
1834

    
1835
#if 0
1836
    {
1837
        float avg;
1838
        AVCodecContext *enc;
1839
        char buf[1024];
1840

1841
        /* feed status */
1842
        stream = first_feed;
1843
        while (stream != NULL) {
1844
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1845
            url_fprintf(pb, "<TABLE>\n");
1846
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1847
            for(i=0;i<stream->nb_streams;i++) {
1848
                AVStream *st = stream->streams[i];
1849
                FeedData *fdata = st->priv_data;
1850
                enc = st->codec;
1851

1852
                avcodec_string(buf, sizeof(buf), enc);
1853
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1854
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1855
                    avg /= enc->frame_size;
1856
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1857
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1858
            }
1859
            url_fprintf(pb, "</TABLE>\n");
1860
            stream = stream->next_feed;
1861
        }
1862
    }
1863
#endif
1864

    
1865
    /* connection status */
1866
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1867

    
1868
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1869
                 nb_connections, nb_max_connections);
1870

    
1871
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<BR>\n",
1872
                 current_bandwidth, max_bandwidth);
1873

    
1874
    url_fprintf(pb, "<TABLE>\n");
1875
    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");
1876
    c1 = first_http_ctx;
1877
    i = 0;
1878
    while (c1 != NULL) {
1879
        int bitrate;
1880
        int j;
1881

    
1882
        bitrate = 0;
1883
        if (c1->stream) {
1884
            for (j = 0; j < c1->stream->nb_streams; j++) {
1885
                if (!c1->stream->feed)
1886
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1887
                else if (c1->feed_streams[j] >= 0)
1888
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1889
            }
1890
        }
1891

    
1892
        i++;
1893
        p = inet_ntoa(c1->from_addr.sin_addr);
1894
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1895
                    i,
1896
                    c1->stream ? c1->stream->filename : "",
1897
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1898
                    p,
1899
                    c1->protocol,
1900
                    http_state[c1->state]);
1901
        fmt_bytecount(pb, bitrate);
1902
        url_fprintf(pb, "<td align=right>");
1903
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1904
        url_fprintf(pb, "<td align=right>");
1905
        fmt_bytecount(pb, c1->data_count);
1906
        url_fprintf(pb, "\n");
1907
        c1 = c1->next;
1908
    }
1909
    url_fprintf(pb, "</TABLE>\n");
1910

    
1911
    /* date */
1912
    ti = time(NULL);
1913
    p = ctime(&ti);
1914
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1915
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1916

    
1917
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1918
    c->buffer_ptr = c->pb_buffer;
1919
    c->buffer_end = c->pb_buffer + len;
1920
}
1921

    
1922
/* check if the parser needs to be opened for stream i */
1923
static void open_parser(AVFormatContext *s, int i)
1924
{
1925
    AVStream *st = s->streams[i];
1926
    AVCodec *codec;
1927

    
1928
    if (!st->codec->codec) {
1929
        codec = avcodec_find_decoder(st->codec->codec_id);
1930
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1931
            st->codec->parse_only = 1;
1932
            if (avcodec_open(st->codec, codec) < 0)
1933
                st->codec->parse_only = 0;
1934
        }
1935
    }
1936
}
1937

    
1938
static int open_input_stream(HTTPContext *c, const char *info)
1939
{
1940
    char buf[128];
1941
    char input_filename[1024];
1942
    AVFormatContext *s;
1943
    int buf_size, i, ret;
1944
    int64_t stream_pos;
1945

    
1946
    /* find file name */
1947
    if (c->stream->feed) {
1948
        strcpy(input_filename, c->stream->feed->feed_filename);
1949
        buf_size = FFM_PACKET_SIZE;
1950
        /* compute position (absolute time) */
1951
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1952
            stream_pos = parse_date(buf, 0);
1953
            if (stream_pos == INT64_MIN)
1954
                return -1;
1955
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1956
            int prebuffer = strtol(buf, 0, 10);
1957
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1958
        } else
1959
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1960
    } else {
1961
        strcpy(input_filename, c->stream->feed_filename);
1962
        buf_size = 0;
1963
        /* compute position (relative time) */
1964
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1965
            stream_pos = parse_date(buf, 1);
1966
            if (stream_pos == INT64_MIN)
1967
                return -1;
1968
        } else
1969
            stream_pos = 0;
1970
    }
1971
    if (input_filename[0] == '\0')
1972
        return -1;
1973

    
1974
#if 0
1975
    { time_t when = stream_pos / 1000000;
1976
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1977
    }
1978
#endif
1979

    
1980
    /* open stream */
1981
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1982
                                  buf_size, c->stream->ap_in)) < 0) {
1983
        http_log("could not open %s: %d\n", input_filename, ret);
1984
        return -1;
1985
    }
1986
    s->flags |= AVFMT_FLAG_GENPTS;
1987
    c->fmt_in = s;
1988
    av_find_stream_info(c->fmt_in);
1989

    
1990
    /* open each parser */
1991
    for(i=0;i<s->nb_streams;i++)
1992
        open_parser(s, i);
1993

    
1994
    /* choose stream as clock source (we favorize video stream if
1995
       present) for packet sending */
1996
    c->pts_stream_index = 0;
1997
    for(i=0;i<c->stream->nb_streams;i++) {
1998
        if (c->pts_stream_index == 0 &&
1999
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2000
            c->pts_stream_index = i;
2001
        }
2002
    }
2003

    
2004
#if 1
2005
    if (c->fmt_in->iformat->read_seek)
2006
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2007
#endif
2008
    /* set the start time (needed for maxtime and RTP packet timing) */
2009
    c->start_time = cur_time;
2010
    c->first_pts = AV_NOPTS_VALUE;
2011
    return 0;
2012
}
2013

    
2014
/* return the server clock (in us) */
2015
static int64_t get_server_clock(HTTPContext *c)
2016
{
2017
    /* compute current pts value from system time */
2018
    return (cur_time - c->start_time) * 1000;
2019
}
2020

    
2021
/* return the estimated time at which the current packet must be sent
2022
   (in us) */
2023
static int64_t get_packet_send_clock(HTTPContext *c)
2024
{
2025
    int bytes_left, bytes_sent, frame_bytes;
2026

    
2027
    frame_bytes = c->cur_frame_bytes;
2028
    if (frame_bytes <= 0)
2029
        return c->cur_pts;
2030
    else {
2031
        bytes_left = c->buffer_end - c->buffer_ptr;
2032
        bytes_sent = frame_bytes - bytes_left;
2033
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2034
    }
2035
}
2036

    
2037

    
2038
static int http_prepare_data(HTTPContext *c)
2039
{
2040
    int i, len, ret;
2041
    AVFormatContext *ctx;
2042

    
2043
    av_freep(&c->pb_buffer);
2044
    switch(c->state) {
2045
    case HTTPSTATE_SEND_DATA_HEADER:
2046
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2047
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2048
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2049
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2050
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2051

    
2052
        for(i=0;i<c->stream->nb_streams;i++) {
2053
            AVStream *st;
2054
            AVStream *src;
2055
            st = av_mallocz(sizeof(AVStream));
2056
            c->fmt_ctx.streams[i] = st;
2057
            /* if file or feed, then just take streams from FFStream struct */
2058
            if (!c->stream->feed ||
2059
                c->stream->feed == c->stream)
2060
                src = c->stream->streams[i];
2061
            else
2062
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2063

    
2064
            *st = *src;
2065
            st->priv_data = 0;
2066
            st->codec->frame_number = 0; /* XXX: should be done in
2067
                                           AVStream, not in codec */
2068
        }
2069
        /* set output format parameters */
2070
        c->fmt_ctx.oformat = c->stream->fmt;
2071
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2072

    
2073
        c->got_key_frame = 0;
2074

    
2075
        /* prepare header and save header data in a stream */
2076
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2077
            /* XXX: potential leak */
2078
            return -1;
2079
        }
2080
        c->fmt_ctx.pb->is_streamed = 1;
2081

    
2082
        /*
2083
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2084
         * Default value from FFmpeg
2085
         * Try to set it use configuration option
2086
         */
2087
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2088
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2089

    
2090
        av_set_parameters(&c->fmt_ctx, NULL);
2091
        if (av_write_header(&c->fmt_ctx) < 0) {
2092
            http_log("Error writing output header\n");
2093
            return -1;
2094
        }
2095

    
2096
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2097
        c->buffer_ptr = c->pb_buffer;
2098
        c->buffer_end = c->pb_buffer + len;
2099

    
2100
        c->state = HTTPSTATE_SEND_DATA;
2101
        c->last_packet_sent = 0;
2102
        break;
2103
    case HTTPSTATE_SEND_DATA:
2104
        /* find a new packet */
2105
        /* read a packet from the input stream */
2106
        if (c->stream->feed)
2107
            ffm_set_write_index(c->fmt_in,
2108
                                c->stream->feed->feed_write_index,
2109
                                c->stream->feed->feed_size);
2110

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

    
2207
                    if (c->is_packetized) {
2208
                        int max_packet_size;
2209
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2210
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2211
                        else
2212
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2213
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2214
                    } else {
2215
                        ret = url_open_dyn_buf(&ctx->pb);
2216
                    }
2217
                    if (ret < 0) {
2218
                        /* XXX: potential leak */
2219
                        return -1;
2220
                    }
2221
                    ost = ctx->streams[pkt.stream_index];
2222

    
2223
                    ctx->pb->is_streamed = 1;
2224
                    if (pkt.dts != AV_NOPTS_VALUE)
2225
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2226
                    if (pkt.pts != AV_NOPTS_VALUE)
2227
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2228
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2229
                    if (av_write_frame(ctx, &pkt) < 0) {
2230
                        http_log("Error writing frame to output\n");
2231
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2232
                    }
2233

    
2234
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2235
                    c->cur_frame_bytes = len;
2236
                    c->buffer_ptr = c->pb_buffer;
2237
                    c->buffer_end = c->pb_buffer + len;
2238

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

    
2266
        c->last_packet_sent = 1;
2267
        break;
2268
    }
2269
    return 0;
2270
}
2271

    
2272
/* should convert the format at the same time */
2273
/* send data starting at c->buffer_ptr to the output connection
2274
   (either UDP or TCP connection) */
2275
static int http_send_data(HTTPContext *c)
2276
{
2277
    int len, ret;
2278

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

    
2308
                c->data_count += len;
2309
                update_datarate(&c->datarate, c->data_count);
2310
                if (c->stream)
2311
                    c->stream->bytes_served += len;
2312

    
2313
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2314
                    /* RTP packets are sent inside the RTSP TCP connection */
2315
                    ByteIOContext *pb;
2316
                    int interleaved_index, size;
2317
                    uint8_t header[4];
2318
                    HTTPContext *rtsp_c;
2319

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

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

    
2383
                c->data_count += len;
2384
                update_datarate(&c->datarate, c->data_count);
2385
                if (c->stream)
2386
                    c->stream->bytes_served += len;
2387
                break;
2388
            }
2389
        }
2390
    } /* for(;;) */
2391
    return 0;
2392
}
2393

    
2394
static int http_start_receive_data(HTTPContext *c)
2395
{
2396
    int fd;
2397

    
2398
    if (c->stream->feed_opened)
2399
        return -1;
2400

    
2401
    /* Don't permit writing to this one */
2402
    if (c->stream->readonly)
2403
        return -1;
2404

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

    
2413
    if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2414
        http_log("Error reading write index from feed file: %s\n", strerror(errno));
2415
        return -1;
2416
    }
2417
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2418
    lseek(fd, 0, SEEK_SET);
2419

    
2420
    /* init buffer input */
2421
    c->buffer_ptr = c->buffer;
2422
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2423
    c->stream->feed_opened = 1;
2424
    return 0;
2425
}
2426

    
2427
static int http_receive_data(HTTPContext *c)
2428
{
2429
    HTTPContext *c1;
2430

    
2431
    if (c->buffer_end > c->buffer_ptr) {
2432
        int len;
2433

    
2434
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2435
        if (len < 0) {
2436
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2437
                ff_neterrno() != FF_NETERROR(EINTR))
2438
                /* error : close connection */
2439
                goto fail;
2440
        } else if (len == 0)
2441
            /* end of connection : close it */
2442
            goto fail;
2443
        else {
2444
            c->buffer_ptr += len;
2445
            c->data_count += len;
2446
            update_datarate(&c->datarate, c->data_count);
2447
        }
2448
    }
2449

    
2450
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2451
        if (c->buffer[0] != 'f' ||
2452
            c->buffer[1] != 'm') {
2453
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2454
            goto fail;
2455
        }
2456
    }
2457

    
2458
    if (c->buffer_ptr >= c->buffer_end) {
2459
        FFStream *feed = c->stream;
2460
        /* a packet has been received : write it in the store, except
2461
           if header */
2462
        if (c->data_count > FFM_PACKET_SIZE) {
2463

    
2464
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2465
            /* XXX: use llseek or url_seek */
2466
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2467
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2468
                http_log("Error writing to feed file: %s\n", strerror(errno));
2469
                goto fail;
2470
            }
2471

    
2472
            feed->feed_write_index += FFM_PACKET_SIZE;
2473
            /* update file size */
2474
            if (feed->feed_write_index > c->stream->feed_size)
2475
                feed->feed_size = feed->feed_write_index;
2476

    
2477
            /* handle wrap around if max file size reached */
2478
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2479
                feed->feed_write_index = FFM_PACKET_SIZE;
2480

    
2481
            /* write index */
2482
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2483
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2484
                goto fail;
2485
            }
2486

    
2487
            /* wake up any waiting connections */
2488
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2489
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2490
                    c1->stream->feed == c->stream->feed)
2491
                    c1->state = HTTPSTATE_SEND_DATA;
2492
            }
2493
        } else {
2494
            /* We have a header in our hands that contains useful data */
2495
            AVFormatContext *s = NULL;
2496
            ByteIOContext *pb;
2497
            AVInputFormat *fmt_in;
2498
            int i;
2499

    
2500
            /* use feed output format name to find corresponding input format */
2501
            fmt_in = av_find_input_format(feed->fmt->name);
2502
            if (!fmt_in)
2503
                goto fail;
2504

    
2505
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2506
            pb->is_streamed = 1;
2507

    
2508
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2509
                av_free(pb);
2510
                goto fail;
2511
            }
2512

    
2513
            /* Now we have the actual streams */
2514
            if (s->nb_streams != feed->nb_streams) {
2515
                av_close_input_stream(s);
2516
                av_free(pb);
2517
                goto fail;
2518
            }
2519

    
2520
            for (i = 0; i < s->nb_streams; i++) {
2521
                AVStream *fst = feed->streams[i];
2522
                AVStream *st = s->streams[i];
2523
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2524
                if (fst->codec->extradata_size) {
2525
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2526
                    if (!fst->codec->extradata)
2527
                        goto fail;
2528
                    memcpy(fst->codec->extradata, st->codec->extradata,
2529
                           fst->codec->extradata_size);
2530
                }
2531
            }
2532

    
2533
            av_close_input_stream(s);
2534
            av_free(pb);
2535
        }
2536
        c->buffer_ptr = c->buffer;
2537
    }
2538

    
2539
    return 0;
2540
 fail:
2541
    c->stream->feed_opened = 0;
2542
    close(c->feed_fd);
2543
    /* wake up any waiting connections to stop waiting for feed */
2544
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2545
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2546
            c1->stream->feed == c->stream->feed)
2547
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2548
    }
2549
    return -1;
2550
}
2551

    
2552
/********************************************************************/
2553
/* RTSP handling */
2554

    
2555
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2556
{
2557
    const char *str;
2558
    time_t ti;
2559
    char *p;
2560
    char buf2[32];
2561

    
2562
    switch(error_number) {
2563
    case RTSP_STATUS_OK:
2564
        str = "OK";
2565
        break;
2566
    case RTSP_STATUS_METHOD:
2567
        str = "Method Not Allowed";
2568
        break;
2569
    case RTSP_STATUS_BANDWIDTH:
2570
        str = "Not Enough Bandwidth";
2571
        break;
2572
    case RTSP_STATUS_SESSION:
2573
        str = "Session Not Found";
2574
        break;
2575
    case RTSP_STATUS_STATE:
2576
        str = "Method Not Valid in This State";
2577
        break;
2578
    case RTSP_STATUS_AGGREGATE:
2579
        str = "Aggregate operation not allowed";
2580
        break;
2581
    case RTSP_STATUS_ONLY_AGGREGATE:
2582
        str = "Only aggregate operation allowed";
2583
        break;
2584
    case RTSP_STATUS_TRANSPORT:
2585
        str = "Unsupported transport";
2586
        break;
2587
    case RTSP_STATUS_INTERNAL:
2588
        str = "Internal Server Error";
2589
        break;
2590
    case RTSP_STATUS_SERVICE:
2591
        str = "Service Unavailable";
2592
        break;
2593
    case RTSP_STATUS_VERSION:
2594
        str = "RTSP Version not supported";
2595
        break;
2596
    default:
2597
        str = "Unknown Error";
2598
        break;
2599
    }
2600

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

    
2604
    /* output GMT time */
2605
    ti = time(NULL);
2606
    p = ctime(&ti);
2607
    strcpy(buf2, p);
2608
    p = buf2 + strlen(p) - 1;
2609
    if (*p == '\n')
2610
        *p = '\0';
2611
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2612
}
2613

    
2614
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2615
{
2616
    rtsp_reply_header(c, error_number);
2617
    url_fprintf(c->pb, "\r\n");
2618
}
2619

    
2620
static int rtsp_parse_request(HTTPContext *c)
2621
{
2622
    const char *p, *p1, *p2;
2623
    char cmd[32];
2624
    char url[1024];
2625
    char protocol[32];
2626
    char line[1024];
2627
    int len;
2628
    RTSPMessageHeader header1, *header = &header1;
2629

    
2630
    c->buffer_ptr[0] = '\0';
2631
    p = c->buffer;
2632

    
2633
    get_word(cmd, sizeof(cmd), &p);
2634
    get_word(url, sizeof(url), &p);
2635
    get_word(protocol, sizeof(protocol), &p);
2636

    
2637
    av_strlcpy(c->method, cmd, sizeof(c->method));
2638
    av_strlcpy(c->url, url, sizeof(c->url));
2639
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2640

    
2641
    if (url_open_dyn_buf(&c->pb) < 0) {
2642
        /* XXX: cannot do more */
2643
        c->pb = NULL; /* safety */
2644
        return -1;
2645
    }
2646

    
2647
    /* check version name */
2648
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2649
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2650
        goto the_end;
2651
    }
2652

    
2653
    /* parse each header line */
2654
    memset(header, 0, sizeof(*header));
2655
    /* skip to next line */
2656
    while (*p != '\n' && *p != '\0')
2657
        p++;
2658
    if (*p == '\n')
2659
        p++;
2660
    while (*p != '\0') {
2661
        p1 = strchr(p, '\n');
2662
        if (!p1)
2663
            break;
2664
        p2 = p1;
2665
        if (p2 > p && p2[-1] == '\r')
2666
            p2--;
2667
        /* skip empty line */
2668
        if (p2 == p)
2669
            break;
2670
        len = p2 - p;
2671
        if (len > sizeof(line) - 1)
2672
            len = sizeof(line) - 1;
2673
        memcpy(line, p, len);
2674
        line[len] = '\0';
2675
        rtsp_parse_line(header, line);
2676
        p = p1 + 1;
2677
    }
2678

    
2679
    /* handle sequence number */
2680
    c->seq = header->seq;
2681

    
2682
    if (!strcmp(cmd, "DESCRIBE"))
2683
        rtsp_cmd_describe(c, url);
2684
    else if (!strcmp(cmd, "OPTIONS"))
2685
        rtsp_cmd_options(c, url);
2686
    else if (!strcmp(cmd, "SETUP"))
2687
        rtsp_cmd_setup(c, url, header);
2688
    else if (!strcmp(cmd, "PLAY"))
2689
        rtsp_cmd_play(c, url, header);
2690
    else if (!strcmp(cmd, "PAUSE"))
2691
        rtsp_cmd_pause(c, url, header);
2692
    else if (!strcmp(cmd, "TEARDOWN"))
2693
        rtsp_cmd_teardown(c, url, header);
2694
    else
2695
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2696

    
2697
 the_end:
2698
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2699
    c->pb = NULL; /* safety */
2700
    if (len < 0) {
2701
        /* XXX: cannot do more */
2702
        return -1;
2703
    }
2704
    c->buffer_ptr = c->pb_buffer;
2705
    c->buffer_end = c->pb_buffer + len;
2706
    c->state = RTSPSTATE_SEND_REPLY;
2707
    return 0;
2708
}
2709

    
2710
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2711
                                   struct in_addr my_ip)
2712
{
2713
    AVFormatContext *avc;
2714
    AVStream avs[MAX_STREAMS];
2715
    int i;
2716

    
2717
    avc =  avformat_alloc_context();
2718
    if (avc == NULL) {
2719
        return -1;
2720
    }
2721
    av_metadata_set(&avc->metadata, "title",
2722
                    stream->title[0] ? stream->title : "No Title");
2723
    avc->nb_streams = stream->nb_streams;
2724
    if (stream->is_multicast) {
2725
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2726
                 inet_ntoa(stream->multicast_ip),
2727
                 stream->multicast_port, stream->multicast_ttl);
2728
    }
2729

    
2730
    for(i = 0; i < stream->nb_streams; i++) {
2731
        avc->streams[i] = &avs[i];
2732
        avc->streams[i]->codec = stream->streams[i]->codec;
2733
    }
2734
    *pbuffer = av_mallocz(2048);
2735
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2736
    av_free(avc);
2737

    
2738
    return strlen(*pbuffer);
2739
}
2740

    
2741
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2742
{
2743
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2744
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2745
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2746
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2747
    url_fprintf(c->pb, "\r\n");
2748
}
2749

    
2750
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2751
{
2752
    FFStream *stream;
2753
    char path1[1024];
2754
    const char *path;
2755
    uint8_t *content;
2756
    int content_length, len;
2757
    struct sockaddr_in my_addr;
2758

    
2759
    /* find which url is asked */
2760
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2761
    path = path1;
2762
    if (*path == '/')
2763
        path++;
2764

    
2765
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2766
        if (!stream->is_feed &&
2767
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2768
            !strcmp(path, stream->filename)) {
2769
            goto found;
2770
        }
2771
    }
2772
    /* no stream found */
2773
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2774
    return;
2775

    
2776
 found:
2777
    /* prepare the media description in sdp format */
2778

    
2779
    /* get the host IP */
2780
    len = sizeof(my_addr);
2781
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2782
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2783
    if (content_length < 0) {
2784
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2785
        return;
2786
    }
2787
    rtsp_reply_header(c, RTSP_STATUS_OK);
2788
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2789
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2790
    url_fprintf(c->pb, "\r\n");
2791
    put_buffer(c->pb, content, content_length);
2792
}
2793

    
2794
static HTTPContext *find_rtp_session(const char *session_id)
2795
{
2796
    HTTPContext *c;
2797

    
2798
    if (session_id[0] == '\0')
2799
        return NULL;
2800

    
2801
    for(c = first_http_ctx; c != NULL; c = c->next) {
2802
        if (!strcmp(c->session_id, session_id))
2803
            return c;
2804
    }
2805
    return NULL;
2806
}
2807

    
2808
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2809
{
2810
    RTSPTransportField *th;
2811
    int i;
2812

    
2813
    for(i=0;i<h->nb_transports;i++) {
2814
        th = &h->transports[i];
2815
        if (th->lower_transport == lower_transport)
2816
            return th;
2817
    }
2818
    return NULL;
2819
}
2820

    
2821
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2822
                           RTSPMessageHeader *h)
2823
{
2824
    FFStream *stream;
2825
    int stream_index, port;
2826
    char buf[1024];
2827
    char path1[1024];
2828
    const char *path;
2829
    HTTPContext *rtp_c;
2830
    RTSPTransportField *th;
2831
    struct sockaddr_in dest_addr;
2832
    RTSPActionServerSetup setup;
2833

    
2834
    /* find which url is asked */
2835
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2836
    path = path1;
2837
    if (*path == '/')
2838
        path++;
2839

    
2840
    /* now check each stream */
2841
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2842
        if (!stream->is_feed &&
2843
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2844
            /* accept aggregate filenames only if single stream */
2845
            if (!strcmp(path, stream->filename)) {
2846
                if (stream->nb_streams != 1) {
2847
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2848
                    return;
2849
                }
2850
                stream_index = 0;
2851
                goto found;
2852
            }
2853

    
2854
            for(stream_index = 0; stream_index < stream->nb_streams;
2855
                stream_index++) {
2856
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2857
                         stream->filename, stream_index);
2858
                if (!strcmp(path, buf))
2859
                    goto found;
2860
            }
2861
        }
2862
    }
2863
    /* no stream found */
2864
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2865
    return;
2866
 found:
2867

    
2868
    /* generate session id if needed */
2869
    if (h->session_id[0] == '\0')
2870
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2871
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2872

    
2873
    /* find rtp session, and create it if none found */
2874
    rtp_c = find_rtp_session(h->session_id);
2875
    if (!rtp_c) {
2876
        /* always prefer UDP */
2877
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2878
        if (!th) {
2879
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2880
            if (!th) {
2881
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2882
                return;
2883
            }
2884
        }
2885

    
2886
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2887
                                   th->lower_transport);
2888
        if (!rtp_c) {
2889
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2890
            return;
2891
        }
2892

    
2893
        /* open input stream */
2894
        if (open_input_stream(rtp_c, "") < 0) {
2895
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2896
            return;
2897
        }
2898
    }
2899

    
2900
    /* test if stream is OK (test needed because several SETUP needs
2901
       to be done for a given file) */
2902
    if (rtp_c->stream != stream) {
2903
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2904
        return;
2905
    }
2906

    
2907
    /* test if stream is already set up */
2908
    if (rtp_c->rtp_ctx[stream_index]) {
2909
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2910
        return;
2911
    }
2912

    
2913
    /* check transport */
2914
    th = find_transport(h, rtp_c->rtp_protocol);
2915
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2916
                th->client_port_min <= 0)) {
2917
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2918
        return;
2919
    }
2920

    
2921
    /* setup default options */
2922
    setup.transport_option[0] = '\0';
2923
    dest_addr = rtp_c->from_addr;
2924
    dest_addr.sin_port = htons(th->client_port_min);
2925

    
2926
    /* setup stream */
2927
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2928
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2929
        return;
2930
    }
2931

    
2932
    /* now everything is OK, so we can send the connection parameters */
2933
    rtsp_reply_header(c, RTSP_STATUS_OK);
2934
    /* session ID */
2935
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2936

    
2937
    switch(rtp_c->rtp_protocol) {
2938
    case RTSP_LOWER_TRANSPORT_UDP:
2939
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2940
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2941
                    "client_port=%d-%d;server_port=%d-%d",
2942
                    th->client_port_min, th->client_port_min + 1,
2943
                    port, port + 1);
2944
        break;
2945
    case RTSP_LOWER_TRANSPORT_TCP:
2946
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2947
                    stream_index * 2, stream_index * 2 + 1);
2948
        break;
2949
    default:
2950
        break;
2951
    }
2952
    if (setup.transport_option[0] != '\0')
2953
        url_fprintf(c->pb, ";%s", setup.transport_option);
2954
    url_fprintf(c->pb, "\r\n");
2955

    
2956

    
2957
    url_fprintf(c->pb, "\r\n");
2958
}
2959

    
2960

    
2961
/* find an rtp connection by using the session ID. Check consistency
2962
   with filename */
2963
static HTTPContext *find_rtp_session_with_url(const char *url,
2964
                                              const char *session_id)
2965
{
2966
    HTTPContext *rtp_c;
2967
    char path1[1024];
2968
    const char *path;
2969
    char buf[1024];
2970
    int s;
2971

    
2972
    rtp_c = find_rtp_session(session_id);
2973
    if (!rtp_c)
2974
        return NULL;
2975

    
2976
    /* find which url is asked */
2977
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2978
    path = path1;
2979
    if (*path == '/')
2980
        path++;
2981
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2982
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2983
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2984
        rtp_c->stream->filename, s);
2985
      if(!strncmp(path, buf, sizeof(buf))) {
2986
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2987
        return rtp_c;
2988
      }
2989
    }
2990
    return NULL;
2991
}
2992

    
2993
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
2994
{
2995
    HTTPContext *rtp_c;
2996

    
2997
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2998
    if (!rtp_c) {
2999
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3000
        return;
3001
    }
3002

    
3003
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3004
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3005
        rtp_c->state != HTTPSTATE_READY) {
3006
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3007
        return;
3008
    }
3009

    
3010
#if 0
3011
    /* XXX: seek in stream */
3012
    if (h->range_start != AV_NOPTS_VALUE) {
3013
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3014
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3015
    }
3016
#endif
3017

    
3018
    rtp_c->state = HTTPSTATE_SEND_DATA;
3019

    
3020
    /* now everything is OK, so we can send the connection parameters */
3021
    rtsp_reply_header(c, RTSP_STATUS_OK);
3022
    /* session ID */
3023
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3024
    url_fprintf(c->pb, "\r\n");
3025
}
3026

    
3027
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3028
{
3029
    HTTPContext *rtp_c;
3030

    
3031
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3032
    if (!rtp_c) {
3033
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3034
        return;
3035
    }
3036

    
3037
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3038
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3039
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3040
        return;
3041
    }
3042

    
3043
    rtp_c->state = HTTPSTATE_READY;
3044
    rtp_c->first_pts = AV_NOPTS_VALUE;
3045
    /* now everything is OK, so we can send the connection parameters */
3046
    rtsp_reply_header(c, RTSP_STATUS_OK);
3047
    /* session ID */
3048
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3049
    url_fprintf(c->pb, "\r\n");
3050
}
3051

    
3052
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3053
{
3054
    HTTPContext *rtp_c;
3055
    char session_id[32];
3056

    
3057
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3058
    if (!rtp_c) {
3059
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3060
        return;
3061
    }
3062

    
3063
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3064

    
3065
    /* abort the session */
3066
    close_connection(rtp_c);
3067

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

    
3075

    
3076
/********************************************************************/
3077
/* RTP handling */
3078

    
3079
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3080
                                       FFStream *stream, const char *session_id,
3081
                                       enum RTSPLowerTransport rtp_protocol)
3082
{
3083
    HTTPContext *c = NULL;
3084
    const char *proto_str;
3085

    
3086
    /* XXX: should output a warning page when coming
3087
       close to the connection limit */
3088
    if (nb_connections >= nb_max_connections)
3089
        goto fail;
3090

    
3091
    /* add a new connection */
3092
    c = av_mallocz(sizeof(HTTPContext));
3093
    if (!c)
3094
        goto fail;
3095

    
3096
    c->fd = -1;
3097
    c->poll_entry = NULL;
3098
    c->from_addr = *from_addr;
3099
    c->buffer_size = IOBUFFER_INIT_SIZE;
3100
    c->buffer = av_malloc(c->buffer_size);
3101
    if (!c->buffer)
3102
        goto fail;
3103
    nb_connections++;
3104
    c->stream = stream;
3105
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3106
    c->state = HTTPSTATE_READY;
3107
    c->is_packetized = 1;
3108
    c->rtp_protocol = rtp_protocol;
3109

    
3110
    /* protocol is shown in statistics */
3111
    switch(c->rtp_protocol) {
3112
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3113
        proto_str = "MCAST";
3114
        break;
3115
    case RTSP_LOWER_TRANSPORT_UDP:
3116
        proto_str = "UDP";
3117
        break;
3118
    case RTSP_LOWER_TRANSPORT_TCP:
3119
        proto_str = "TCP";
3120
        break;
3121
    default:
3122
        proto_str = "???";
3123
        break;
3124
    }
3125
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3126
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3127

    
3128
    current_bandwidth += stream->bandwidth;
3129

    
3130
    c->next = first_http_ctx;
3131
    first_http_ctx = c;
3132
    return c;
3133

    
3134
 fail:
3135
    if (c) {
3136
        av_free(c->buffer);
3137
        av_free(c);
3138
    }
3139
    return NULL;
3140
}
3141

    
3142
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3143
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3144
   used. */
3145
static int rtp_new_av_stream(HTTPContext *c,
3146
                             int stream_index, struct sockaddr_in *dest_addr,
3147
                             HTTPContext *rtsp_c)
3148
{
3149
    AVFormatContext *ctx;
3150
    AVStream *st;
3151
    char *ipaddr;
3152
    URLContext *h = NULL;
3153
    uint8_t *dummy_buf;
3154
    int max_packet_size;
3155

    
3156
    /* now we can open the relevant output stream */
3157
    ctx = avformat_alloc_context();
3158
    if (!ctx)
3159
        return -1;
3160
    ctx->oformat = guess_format("rtp", NULL, NULL);
3161

    
3162
    st = av_mallocz(sizeof(AVStream));
3163
    if (!st)
3164
        goto fail;
3165
    st->codec= avcodec_alloc_context();
3166
    ctx->nb_streams = 1;
3167
    ctx->streams[0] = st;
3168

    
3169
    if (!c->stream->feed ||
3170
        c->stream->feed == c->stream)
3171
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3172
    else
3173
        memcpy(st,
3174
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3175
               sizeof(AVStream));
3176
    st->priv_data = NULL;
3177

    
3178
    /* build destination RTP address */
3179
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3180

    
3181
    switch(c->rtp_protocol) {
3182
    case RTSP_LOWER_TRANSPORT_UDP:
3183
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3184
        /* RTP/UDP case */
3185

    
3186
        /* XXX: also pass as parameter to function ? */
3187
        if (c->stream->is_multicast) {
3188
            int ttl;
3189
            ttl = c->stream->multicast_ttl;
3190
            if (!ttl)
3191
                ttl = 16;
3192
            snprintf(ctx->filename, sizeof(ctx->filename),
3193
                     "rtp://%s:%d?multicast=1&ttl=%d",
3194
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3195
        } else {
3196
            snprintf(ctx->filename, sizeof(ctx->filename),
3197
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3198
        }
3199

    
3200
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3201
            goto fail;
3202
        c->rtp_handles[stream_index] = h;
3203
        max_packet_size = url_get_max_packet_size(h);
3204
        break;
3205
    case RTSP_LOWER_TRANSPORT_TCP:
3206
        /* RTP/TCP case */
3207
        c->rtsp_c = rtsp_c;
3208
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3209
        break;
3210
    default:
3211
        goto fail;
3212
    }
3213

    
3214
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3215
             ipaddr, ntohs(dest_addr->sin_port),
3216
             c->stream->filename, stream_index, c->protocol);
3217

    
3218
    /* normally, no packets should be output here, but the packet size may be checked */
3219
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3220
        /* XXX: close stream */
3221
        goto fail;
3222
    }
3223
    av_set_parameters(ctx, NULL);
3224
    if (av_write_header(ctx) < 0) {
3225
    fail:
3226
        if (h)
3227
            url_close(h);
3228
        av_free(ctx);
3229
        return -1;
3230
    }
3231
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3232
    av_free(dummy_buf);
3233

    
3234
    c->rtp_ctx[stream_index] = ctx;
3235
    return 0;
3236
}
3237

    
3238
/********************************************************************/
3239
/* ffserver initialization */
3240

    
3241
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3242
{
3243
    AVStream *fst;
3244

    
3245
    fst = av_mallocz(sizeof(AVStream));
3246
    if (!fst)
3247
        return NULL;
3248
    fst->codec= avcodec_alloc_context();
3249
    fst->priv_data = av_mallocz(sizeof(FeedData));
3250
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3251
    fst->index = stream->nb_streams;
3252
    av_set_pts_info(fst, 33, 1, 90000);
3253
    stream->streams[stream->nb_streams++] = fst;
3254
    return fst;
3255
}
3256

    
3257
/* return the stream number in the feed */
3258
static int add_av_stream(FFStream *feed, AVStream *st)
3259
{
3260
    AVStream *fst;
3261
    AVCodecContext *av, *av1;
3262
    int i;
3263

    
3264
    av = st->codec;
3265
    for(i=0;i<feed->nb_streams;i++) {
3266
        st = feed->streams[i];
3267
        av1 = st->codec;
3268
        if (av1->codec_id == av->codec_id &&
3269
            av1->codec_type == av->codec_type &&
3270
            av1->bit_rate == av->bit_rate) {
3271

    
3272
            switch(av->codec_type) {
3273
            case CODEC_TYPE_AUDIO:
3274
                if (av1->channels == av->channels &&
3275
                    av1->sample_rate == av->sample_rate)
3276
                    goto found;
3277
                break;
3278
            case CODEC_TYPE_VIDEO:
3279
                if (av1->width == av->width &&
3280
                    av1->height == av->height &&
3281
                    av1->time_base.den == av->time_base.den &&
3282
                    av1->time_base.num == av->time_base.num &&
3283
                    av1->gop_size == av->gop_size)
3284
                    goto found;
3285
                break;
3286
            default:
3287
                abort();
3288
            }
3289
        }
3290
    }
3291

    
3292
    fst = add_av_stream1(feed, av);
3293
    if (!fst)
3294
        return -1;
3295
    return feed->nb_streams - 1;
3296
 found:
3297
    return i;
3298
}
3299

    
3300
static void remove_stream(FFStream *stream)
3301
{
3302
    FFStream **ps;
3303
    ps = &first_stream;
3304
    while (*ps != NULL) {
3305
        if (*ps == stream)
3306
            *ps = (*ps)->next;
3307
        else
3308
            ps = &(*ps)->next;
3309
    }
3310
}
3311

    
3312
/* specific mpeg4 handling : we extract the raw parameters */
3313
static void extract_mpeg4_header(AVFormatContext *infile)
3314
{
3315
    int mpeg4_count, i, size;
3316
    AVPacket pkt;
3317
    AVStream *st;
3318
    const uint8_t *p;
3319

    
3320
    mpeg4_count = 0;
3321
    for(i=0;i<infile->nb_streams;i++) {
3322
        st = infile->streams[i];
3323
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3324
            st->codec->extradata_size == 0) {
3325
            mpeg4_count++;
3326
        }
3327
    }
3328
    if (!mpeg4_count)
3329
        return;
3330

    
3331
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3332
    while (mpeg4_count > 0) {
3333
        if (av_read_packet(infile, &pkt) < 0)
3334
            break;
3335
        st = infile->streams[pkt.stream_index];
3336
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3337
            st->codec->extradata_size == 0) {
3338
            av_freep(&st->codec->extradata);
3339
            /* fill extradata with the header */
3340
            /* XXX: we make hard suppositions here ! */
3341
            p = pkt.data;
3342
            while (p < pkt.data + pkt.size - 4) {
3343
                /* stop when vop header is found */
3344
                if (p[0] == 0x00 && p[1] == 0x00 &&
3345
                    p[2] == 0x01 && p[3] == 0xb6) {
3346
                    size = p - pkt.data;
3347
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3348
                    st->codec->extradata = av_malloc(size);
3349
                    st->codec->extradata_size = size;
3350
                    memcpy(st->codec->extradata, pkt.data, size);
3351
                    break;
3352
                }
3353
                p++;
3354
            }
3355
            mpeg4_count--;
3356
        }
3357
        av_free_packet(&pkt);
3358
    }
3359
}
3360

    
3361
/* compute the needed AVStream for each file */
3362
static void build_file_streams(void)
3363
{
3364
    FFStream *stream, *stream_next;
3365
    AVFormatContext *infile;
3366
    int i, ret;
3367

    
3368
    /* gather all streams */
3369
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3370
        stream_next = stream->next;
3371
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3372
            !stream->feed) {
3373
            /* the stream comes from a file */
3374
            /* try to open the file */
3375
            /* open stream */
3376
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3377
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3378
                /* specific case : if transport stream output to RTP,
3379
                   we use a raw transport stream reader */
3380
                stream->ap_in->mpeg2ts_raw = 1;
3381
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3382
            }
3383

    
3384
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3385
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3386
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3387
                /* remove stream (no need to spend more time on it) */
3388
            fail:
3389
                remove_stream(stream);
3390
            } else {
3391
                /* find all the AVStreams inside and reference them in
3392
                   'stream' */
3393
                if (av_find_stream_info(infile) < 0) {
3394
                    http_log("Could not find codec parameters from '%s'\n",
3395
                             stream->feed_filename);
3396
                    av_close_input_file(infile);
3397
                    goto fail;
3398
                }
3399
                extract_mpeg4_header(infile);
3400

    
3401
                for(i=0;i<infile->nb_streams;i++)
3402
                    add_av_stream1(stream, infile->streams[i]->codec);
3403

    
3404
                av_close_input_file(infile);
3405
            }
3406
        }
3407
    }
3408
}
3409

    
3410
/* compute the needed AVStream for each feed */
3411
static void build_feed_streams(void)
3412
{
3413
    FFStream *stream, *feed;
3414
    int i;
3415

    
3416
    /* gather all streams */
3417
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3418
        feed = stream->feed;
3419
        if (feed) {
3420
            if (!stream->is_feed) {
3421
                /* we handle a stream coming from a feed */
3422
                for(i=0;i<stream->nb_streams;i++)
3423
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3424
            }
3425
        }
3426
    }
3427

    
3428
    /* gather all streams */
3429
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3430
        feed = stream->feed;
3431
        if (feed) {
3432
            if (stream->is_feed) {
3433
                for(i=0;i<stream->nb_streams;i++)
3434
                    stream->feed_streams[i] = i;
3435
            }
3436
        }
3437
    }
3438

    
3439
    /* create feed files if needed */
3440
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3441
        int fd;
3442

    
3443
        if (url_exist(feed->feed_filename)) {
3444
            /* See if it matches */
3445
            AVFormatContext *s;
3446
            int matches = 0;
3447

    
3448
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3449
                /* Now see if it matches */
3450
                if (s->nb_streams == feed->nb_streams) {
3451
                    matches = 1;
3452
                    for(i=0;i<s->nb_streams;i++) {
3453
                        AVStream *sf, *ss;
3454
                        sf = feed->streams[i];
3455
                        ss = s->streams[i];
3456

    
3457
                        if (sf->index != ss->index ||
3458
                            sf->id != ss->id) {
3459
                            http_log("Index & Id do not match for stream %d (%s)\n",
3460
                                   i, feed->feed_filename);
3461
                            matches = 0;
3462
                        } else {
3463
                            AVCodecContext *ccf, *ccs;
3464

    
3465
                            ccf = sf->codec;
3466
                            ccs = ss->codec;
3467
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3468

    
3469
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3470
                                http_log("Codecs do not match for stream %d\n", i);
3471
                                matches = 0;
3472
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3473
                                http_log("Codec bitrates do not match for stream %d\n", i);
3474
                                matches = 0;
3475
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3476
                                if (CHECK_CODEC(time_base.den) ||
3477
                                    CHECK_CODEC(time_base.num) ||
3478
                                    CHECK_CODEC(width) ||
3479
                                    CHECK_CODEC(height)) {
3480
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3481
                                    matches = 0;
3482
                                }
3483
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3484
                                if (CHECK_CODEC(sample_rate) ||
3485
                                    CHECK_CODEC(channels) ||
3486
                                    CHECK_CODEC(frame_size)) {
3487
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3488
                                    matches = 0;
3489
                                }
3490
                            } else {
3491
                                http_log("Unknown codec type\n");
3492
                                matches = 0;
3493
                            }
3494
                        }
3495
                        if (!matches)
3496
                            break;
3497
                    }
3498
                } else
3499
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3500
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3501

    
3502
                av_close_input_file(s);
3503
            } else
3504
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3505
                        feed->feed_filename);
3506

    
3507
            if (!matches) {
3508
                if (feed->readonly) {
3509
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3510
                        feed->feed_filename);
3511
                    exit(1);
3512
                }
3513
                unlink(feed->feed_filename);
3514
            }
3515
        }
3516
        if (!url_exist(feed->feed_filename)) {
3517
            AVFormatContext s1 = {0}, *s = &s1;
3518

    
3519
            if (feed->readonly) {
3520
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3521
                    feed->feed_filename);
3522
                exit(1);
3523
            }
3524

    
3525
            /* only write the header of the ffm file */
3526
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3527
                http_log("Could not open output feed file '%s'\n",
3528
                         feed->feed_filename);
3529
                exit(1);
3530
            }
3531
            s->oformat = feed->fmt;
3532
            s->nb_streams = feed->nb_streams;
3533
            for(i=0;i<s->nb_streams;i++) {
3534
                AVStream *st;
3535
                st = feed->streams[i];
3536
                s->streams[i] = st;
3537
            }
3538
            av_set_parameters(s, NULL);
3539
            if (av_write_header(s) < 0) {
3540
                http_log("Container doesn't supports the required parameters\n");
3541
                exit(1);
3542
            }
3543
            /* XXX: need better api */
3544
            av_freep(&s->priv_data);
3545
            url_fclose(s->pb);
3546
        }
3547
        /* get feed size and write index */
3548
        fd = open(feed->feed_filename, O_RDONLY);
3549
        if (fd < 0) {
3550
            http_log("Could not open output feed file '%s'\n",
3551
                    feed->feed_filename);
3552
            exit(1);
3553
        }
3554

    
3555
        feed->feed_write_index = ffm_read_write_index(fd);
3556
        feed->feed_size = lseek(fd, 0, SEEK_END);
3557
        /* ensure that we do not wrap before the end of file */
3558
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3559
            feed->feed_max_size = feed->feed_size;
3560

    
3561
        close(fd);
3562
    }
3563
}
3564

    
3565
/* compute the bandwidth used by each stream */
3566
static void compute_bandwidth(void)
3567
{
3568
    unsigned bandwidth;
3569
    int i;
3570
    FFStream *stream;
3571

    
3572
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3573
        bandwidth = 0;
3574
        for(i=0;i<stream->nb_streams;i++) {
3575
            AVStream *st = stream->streams[i];
3576
            switch(st->codec->codec_type) {
3577
            case CODEC_TYPE_AUDIO:
3578
            case CODEC_TYPE_VIDEO:
3579
                bandwidth += st->codec->bit_rate;
3580
                break;
3581
            default:
3582
                break;
3583
            }
3584
        }
3585
        stream->bandwidth = (bandwidth + 999) / 1000;
3586
    }
3587
}
3588

    
3589
static void get_arg(char *buf, int buf_size, const char **pp)
3590
{
3591
    const char *p;
3592
    char *q;
3593
    int quote;
3594

    
3595
    p = *pp;
3596
    while (isspace(*p)) p++;
3597
    q = buf;
3598
    quote = 0;
3599
    if (*p == '\"' || *p == '\'')
3600
        quote = *p++;
3601
    for(;;) {
3602
        if (quote) {
3603
            if (*p == quote)
3604
                break;
3605
        } else {
3606
            if (isspace(*p))
3607
                break;
3608
        }
3609
        if (*p == '\0')
3610
            break;
3611
        if ((q - buf) < buf_size - 1)
3612
            *q++ = *p;
3613
        p++;
3614
    }
3615
    *q = '\0';
3616
    if (quote && *p == quote)
3617
        p++;
3618
    *pp = p;
3619
}
3620

    
3621
/* add a codec and set the default parameters */
3622
static void add_codec(FFStream *stream, AVCodecContext *av)
3623
{
3624
    AVStream *st;
3625

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

    
3660
        if (!av->nsse_weight)
3661
            av->nsse_weight = 8;
3662

    
3663
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3664
        av->me_method = ME_EPZS;
3665
        av->rc_buffer_aggressivity = 1.0;
3666

    
3667
        if (!av->rc_eq)
3668
            av->rc_eq = "tex^qComp";
3669
        if (!av->i_quant_factor)
3670
            av->i_quant_factor = -0.8;
3671
        if (!av->b_quant_factor)
3672
            av->b_quant_factor = 1.25;
3673
        if (!av->b_quant_offset)
3674
            av->b_quant_offset = 1.25;
3675
        if (!av->rc_max_rate)
3676
            av->rc_max_rate = av->bit_rate * 2;
3677

    
3678
        if (av->rc_max_rate && !av->rc_buffer_size) {
3679
            av->rc_buffer_size = av->rc_max_rate;
3680
        }
3681

    
3682

    
3683
        break;
3684
    default:
3685
        abort();
3686
    }
3687

    
3688
    st = av_mallocz(sizeof(AVStream));
3689
    if (!st)
3690
        return;
3691
    st->codec = avcodec_alloc_context();
3692
    stream->streams[stream->nb_streams++] = st;
3693
    memcpy(st->codec, av, sizeof(AVCodecContext));
3694
}
3695

    
3696
static enum CodecID opt_audio_codec(const char *arg)
3697
{
3698
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3699

    
3700
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3701
        return CODEC_ID_NONE;
3702

    
3703
    return p->id;
3704
}
3705

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

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

    
3713
    return p->id;
3714
}
3715

    
3716
/* simplistic plugin support */
3717

    
3718
#if HAVE_DLOPEN
3719
static void load_module(const char *filename)
3720
{
3721
    void *dll;
3722
    void (*init_func)(void);
3723
    dll = dlopen(filename, RTLD_NOW);
3724
    if (!dll) {
3725
        fprintf(stderr, "Could not load module '%s' - %s\n",
3726
                filename, dlerror());
3727
        return;
3728
    }
3729

    
3730
    init_func = dlsym(dll, "ffserver_module_init");
3731
    if (!init_func) {
3732
        fprintf(stderr,
3733
                "%s: init function 'ffserver_module_init()' not found\n",
3734
                filename);
3735
        dlclose(dll);
3736
    }
3737

    
3738
    init_func();
3739
}
3740
#endif
3741

    
3742
static int ffserver_opt_default(const char *opt, const char *arg,
3743
                       AVCodecContext *avctx, int type)
3744
{
3745
    int ret = 0;
3746
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3747
    if(o)
3748
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3749
    return ret;
3750
}
3751

    
3752
static int parse_ffconfig(const char *filename)
3753
{
3754
    FILE *f;
3755
    char line[1024];
3756
    char cmd[64];
3757
    char arg[1024];
3758
    const char *p;
3759
    int val, errors, line_num;
3760
    FFStream **last_stream, *stream, *redirect;
3761
    FFStream **last_feed, *feed, *s;
3762
    AVCodecContext audio_enc, video_enc;
3763
    enum CodecID audio_id, video_id;
3764

    
3765
    f = fopen(filename, "r");
3766
    if (!f) {
3767
        perror(filename);
3768
        return -1;
3769
    }
3770

    
3771
    errors = 0;
3772
    line_num = 0;
3773
    first_stream = NULL;
3774
    last_stream = &first_stream;
3775
    first_feed = NULL;
3776
    last_feed = &first_feed;
3777
    stream = NULL;
3778
    feed = NULL;
3779
    redirect = NULL;
3780
    audio_id = CODEC_ID_NONE;
3781
    video_id = CODEC_ID_NONE;
3782
    for(;;) {
3783
        if (fgets(line, sizeof(line), f) == NULL)
3784
            break;
3785
        line_num++;
3786
        p = line;
3787
        while (isspace(*p))
3788
            p++;
3789
        if (*p == '\0' || *p == '#')
3790
            continue;
3791

    
3792
        get_arg(cmd, sizeof(cmd), &p);
3793

    
3794
        if (!strcasecmp(cmd, "Port")) {
3795
            get_arg(arg, sizeof(arg), &p);
3796
            val = atoi(arg);
3797
            if (val < 1 || val > 65536) {
3798
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3799
                        filename, line_num, arg);
3800
                errors++;
3801
            }
3802
            my_http_addr.sin_port = htons(val);
3803
        } else if (!strcasecmp(cmd, "BindAddress")) {
3804
            get_arg(arg, sizeof(arg), &p);
3805
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3806
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3807
                        filename, line_num, arg);
3808
                errors++;
3809
            }
3810
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3811
            ffserver_daemon = 0;
3812
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3813
            get_arg(arg, sizeof(arg), &p);
3814
            val = atoi(arg);
3815
            if (val < 1 || val > 65536) {
3816
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3817
                        filename, line_num, arg);
3818
                errors++;
3819
            }
3820
            my_rtsp_addr.sin_port = htons(atoi(arg));
3821
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3822
            get_arg(arg, sizeof(arg), &p);
3823
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3824
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3825
                        filename, line_num, arg);
3826
                errors++;
3827
            }
3828
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3829
            get_arg(arg, sizeof(arg), &p);
3830
            val = atoi(arg);
3831
            if (val < 1 || val > 65536) {
3832
                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3833
                        filename, line_num, arg);
3834
                errors++;
3835
            }
3836
            nb_max_http_connections = val;
3837
        } else if (!strcasecmp(cmd, "MaxClients")) {
3838
            get_arg(arg, sizeof(arg), &p);
3839
            val = atoi(arg);
3840
            if (val < 1 || val > nb_max_http_connections) {
3841
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3842
                        filename, line_num, arg);
3843
                errors++;
3844
            } else {
3845
                nb_max_connections = val;
3846
            }
3847
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3848
            int64_t llval;
3849
            get_arg(arg, sizeof(arg), &p);
3850
            llval = atoll(arg);
3851
            if (llval < 10 || llval > 10000000) {
3852
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3853
                        filename, line_num, arg);
3854
                errors++;
3855
            } else
3856
                max_bandwidth = llval;
3857
        } else if (!strcasecmp(cmd, "CustomLog")) {
3858
            if (!ffserver_debug)
3859
                get_arg(logfilename, sizeof(logfilename), &p);
3860
        } else if (!strcasecmp(cmd, "<Feed")) {
3861
            /*********************************************/
3862
            /* Feed related options */
3863
            char *q;
3864
            if (stream || feed) {
3865
                fprintf(stderr, "%s:%d: Already in a tag\n",
3866
                        filename, line_num);
3867
            } else {
3868
                feed = av_mallocz(sizeof(FFStream));
3869
                get_arg(feed->filename, sizeof(feed->filename), &p);
3870
                q = strrchr(feed->filename, '>');
3871
                if (*q)
3872
                    *q = '\0';
3873

    
3874
                for (s = first_feed; s; s = s->next) {
3875
                    if (!strcmp(feed->filename, s->filename)) {
3876
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3877
                                filename, line_num, s->filename);
3878
                        errors++;
3879
                    }
3880
                }
3881

    
3882
                feed->fmt = guess_format("ffm", NULL, NULL);
3883
                /* defaut feed file */
3884
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3885
                         "/tmp/%s.ffm", feed->filename);
3886
                feed->feed_max_size = 5 * 1024 * 1024;
3887
                feed->is_feed = 1;
3888
                feed->feed = feed; /* self feeding :-) */
3889

    
3890
                /* add in stream list */
3891
                *last_stream = feed;
3892
                last_stream = &feed->next;
3893
                /* add in feed list */
3894
                *last_feed = feed;
3895
                last_feed = &feed->next_feed;
3896
            }
3897
        } else if (!strcasecmp(cmd, "Launch")) {
3898
            if (feed) {
3899
                int i;
3900

    
3901
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3902

    
3903
                for (i = 0; i < 62; i++) {
3904
                    get_arg(arg, sizeof(arg), &p);
3905
                    if (!arg[0])
3906
                        break;
3907

    
3908
                    feed->child_argv[i] = av_strdup(arg);
3909
                }
3910

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

    
3913
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3914
                    "http://%s:%d/%s",
3915
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3916
                    inet_ntoa(my_http_addr.sin_addr),
3917
                    ntohs(my_http_addr.sin_port), feed->filename);
3918
            }
3919
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3920
            if (feed) {
3921
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3922
                feed->readonly = 1;
3923
            } else if (stream) {
3924
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3925
            }
3926
        } else if (!strcasecmp(cmd, "File")) {
3927
            if (feed) {
3928
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3929
            } else if (stream)
3930
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3931
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3932
            if (feed) {
3933
                char *p1;
3934
                double fsize;
3935

    
3936
                get_arg(arg, sizeof(arg), &p);
3937
                p1 = arg;
3938
                fsize = strtod(p1, &p1);
3939
                switch(toupper(*p1)) {
3940
                case 'K':
3941
                    fsize *= 1024;
3942
                    break;
3943
                case 'M':
3944
                    fsize *= 1024 * 1024;
3945
                    break;
3946
                case 'G':
3947
                    fsize *= 1024 * 1024 * 1024;
3948
                    break;
3949
                }
3950
                feed->feed_max_size = (int64_t)fsize;
3951
            }
3952
        } else if (!strcasecmp(cmd, "</Feed>")) {
3953
            if (!feed) {
3954
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3955
                        filename, line_num);
3956
                errors++;
3957
            }
3958
            feed = NULL;
3959
        } else if (!strcasecmp(cmd, "<Stream")) {
3960
            /*********************************************/
3961
            /* Stream related options */
3962
            char *q;
3963
            if (stream || feed) {
3964
                fprintf(stderr, "%s:%d: Already in a tag\n",
3965
                        filename, line_num);
3966
            } else {
3967
                FFStream *s;
3968
                const AVClass *class;
3969
                stream = av_mallocz(sizeof(FFStream));
3970
                get_arg(stream->filename, sizeof(stream->filename), &p);
3971
                q = strrchr(stream->filename, '>');
3972
                if (*q)
3973
                    *q = '\0';
3974

    
3975
                for (s = first_stream; s; s = s->next) {
3976
                    if (!strcmp(stream->filename, s->filename)) {
3977
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
3978
                                filename, line_num, s->filename);
3979
                        errors++;
3980
                    }
3981
                }
3982

    
3983
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3984
                /* fetch avclass so AVOption works
3985
                 * FIXME try to use avcodec_get_context_defaults2
3986
                 * without changing defaults too much */
3987
                avcodec_get_context_defaults(&video_enc);
3988
                class = video_enc.av_class;
3989
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3990
                memset(&video_enc, 0, sizeof(AVCodecContext));
3991
                audio_enc.av_class = class;
3992
                video_enc.av_class = class;
3993
                audio_id = CODEC_ID_NONE;
3994
                video_id = CODEC_ID_NONE;
3995
                if (stream->fmt) {
3996
                    audio_id = stream->fmt->audio_codec;
3997
                    video_id = stream->fmt->video_codec;
3998
                }
3999

    
4000
                *last_stream = stream;
4001
                last_stream = &stream->next;
4002
            }
4003
        } else if (!strcasecmp(cmd, "Feed")) {
4004
            get_arg(arg, sizeof(arg), &p);
4005
            if (stream) {
4006
                FFStream *sfeed;
4007

    
4008
                sfeed = first_feed;
4009
                while (sfeed != NULL) {
4010
                    if (!strcmp(sfeed->filename, arg))
4011
                        break;
4012
                    sfeed = sfeed->next_feed;
4013
                }
4014
                if (!sfeed)
4015
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4016
                            filename, line_num, arg);
4017
                else
4018
                    stream->feed = sfeed;
4019
            }
4020
        } else if (!strcasecmp(cmd, "Format")) {
4021
            get_arg(arg, sizeof(arg), &p);
4022
            if (stream) {
4023
                if (!strcmp(arg, "status")) {
4024
                    stream->stream_type = STREAM_TYPE_STATUS;
4025
                    stream->fmt = NULL;
4026
                } else {
4027
                    stream->stream_type = STREAM_TYPE_LIVE;
4028
                    /* jpeg cannot be used here, so use single frame jpeg */
4029
                    if (!strcmp(arg, "jpeg"))
4030
                        strcpy(arg, "mjpeg");
4031
                    stream->fmt = guess_stream_format(arg, NULL, NULL);
4032
                    if (!stream->fmt) {
4033
                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4034
                                filename, line_num, arg);
4035
                        errors++;
4036
                    }
4037
                }
4038
                if (stream->fmt) {
4039
                    audio_id = stream->fmt->audio_codec;
4040
                    video_id = stream->fmt->video_codec;
4041
                }
4042
            }
4043
        } else if (!strcasecmp(cmd, "InputFormat")) {
4044
            get_arg(arg, sizeof(arg), &p);
4045
            if (stream) {
4046
                stream->ifmt = av_find_input_format(arg);
4047
                if (!stream->ifmt) {
4048
                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4049
                            filename, line_num, arg);
4050
                }
4051
            }
4052
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4053
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4054
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4055
            } else {
4056
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4057
                            filename, line_num);
4058
                errors++;
4059
            }
4060
        } else if (!strcasecmp(cmd, "Author")) {
4061
            if (stream)
4062
                get_arg(stream->author, sizeof(stream->author), &p);
4063
        } else if (!strcasecmp(cmd, "Comment")) {
4064
            if (stream)
4065
                get_arg(stream->comment, sizeof(stream->comment), &p);
4066
        } else if (!strcasecmp(cmd, "Copyright")) {
4067
            if (stream)
4068
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4069
        } else if (!strcasecmp(cmd, "Title")) {
4070
            if (stream)
4071
                get_arg(stream->title, sizeof(stream->title), &p);
4072
        } else if (!strcasecmp(cmd, "Preroll")) {
4073
            get_arg(arg, sizeof(arg), &p);
4074
            if (stream)
4075
                stream->prebuffer = atof(arg) * 1000;
4076
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4077
            if (stream)
4078
                stream->send_on_key = 1;
4079
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4080
            get_arg(arg, sizeof(arg), &p);
4081
            audio_id = opt_audio_codec(arg);
4082
            if (audio_id == CODEC_ID_NONE) {
4083
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4084
                        filename, line_num, arg);
4085
                errors++;
4086
            }
4087
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4088
            get_arg(arg, sizeof(arg), &p);
4089
            video_id = opt_video_codec(arg);
4090
            if (video_id == CODEC_ID_NONE) {
4091
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4092
                        filename, line_num, arg);
4093
                errors++;
4094
            }
4095
        } else if (!strcasecmp(cmd, "MaxTime")) {
4096
            get_arg(arg, sizeof(arg), &p);
4097
            if (stream)
4098
                stream->max_time = atof(arg) * 1000;
4099
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4100
            get_arg(arg, sizeof(arg), &p);
4101
            if (stream)
4102
                audio_enc.bit_rate = atoi(arg) * 1000;
4103
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4104
            get_arg(arg, sizeof(arg), &p);
4105
            if (stream)
4106
                audio_enc.channels = atoi(arg);
4107
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4108
            get_arg(arg, sizeof(arg), &p);
4109
            if (stream)
4110
                audio_enc.sample_rate = atoi(arg);
4111
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4112
            get_arg(arg, sizeof(arg), &p);
4113
            if (stream) {
4114
//                audio_enc.quality = atof(arg) * 1000;
4115
            }
4116
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4117
            if (stream) {
4118
                int minrate, maxrate;
4119

    
4120
                get_arg(arg, sizeof(arg), &p);
4121

    
4122
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4123
                    video_enc.rc_min_rate = minrate * 1000;
4124
                    video_enc.rc_max_rate = maxrate * 1000;
4125
                } else {
4126
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4127
                            filename, line_num, arg);
4128
                    errors++;
4129
                }
4130
            }
4131
        } else if (!strcasecmp(cmd, "Debug")) {
4132
            if (stream) {
4133
                get_arg(arg, sizeof(arg), &p);
4134
                video_enc.debug = strtol(arg,0,0);
4135
            }
4136
        } else if (!strcasecmp(cmd, "Strict")) {
4137
            if (stream) {
4138
                get_arg(arg, sizeof(arg), &p);
4139
                video_enc.strict_std_compliance = atoi(arg);
4140
            }
4141
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4142
            if (stream) {
4143
                get_arg(arg, sizeof(arg), &p);
4144
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4145
            }
4146
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4147
            if (stream) {
4148
                get_arg(arg, sizeof(arg), &p);
4149
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4150
            }
4151
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4152
            get_arg(arg, sizeof(arg), &p);
4153
            if (stream) {
4154
                video_enc.bit_rate = atoi(arg) * 1000;
4155
            }
4156
        } else if (!strcasecmp(cmd, "VideoSize")) {
4157
            get_arg(arg, sizeof(arg), &p);
4158
            if (stream) {
4159
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4160
                if ((video_enc.width % 16) != 0 ||
4161
                    (video_enc.height % 16) != 0) {
4162
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4163
                            filename, line_num);
4164
                    errors++;
4165
                }
4166
            }
4167
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4168
            get_arg(arg, sizeof(arg), &p);
4169
            if (stream) {
4170
                AVRational frame_rate;
4171
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4172
                    fprintf(stderr, "Incorrect frame rate\n");
4173
                    errors++;
4174
                } else {
4175
                    video_enc.time_base.num = frame_rate.den;
4176
                    video_enc.time_base.den = frame_rate.num;
4177
                }
4178
            }
4179
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4180
            get_arg(arg, sizeof(arg), &p);
4181
            if (stream)
4182
                video_enc.gop_size = atoi(arg);
4183
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4184
            if (stream)
4185
                video_enc.gop_size = 1;
4186
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4187
            if (stream)
4188
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4189
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4190
            if (stream) {
4191
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4192
                video_enc.flags |= CODEC_FLAG_4MV;
4193
            }
4194
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4195
                   !strcasecmp(cmd, "AVOptionAudio")) {
4196
            char arg2[1024];
4197
            AVCodecContext *avctx;
4198
            int type;
4199
            get_arg(arg, sizeof(arg), &p);
4200
            get_arg(arg2, sizeof(arg2), &p);
4201
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4202
                avctx = &video_enc;
4203
                type = AV_OPT_FLAG_VIDEO_PARAM;
4204
            } else {
4205
                avctx = &audio_enc;
4206
                type = AV_OPT_FLAG_AUDIO_PARAM;
4207
            }
4208
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4209
                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4210
                errors++;
4211
            }
4212
        } else if (!strcasecmp(cmd, "VideoTag")) {
4213
            get_arg(arg, sizeof(arg), &p);
4214
            if ((strlen(arg) == 4) && stream)
4215
                video_enc.codec_tag = AV_RL32(arg);
4216
        } else if (!strcasecmp(cmd, "BitExact")) {
4217
            if (stream)
4218
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4219
        } else if (!strcasecmp(cmd, "DctFastint")) {
4220
            if (stream)
4221
                video_enc.dct_algo  = FF_DCT_FASTINT;
4222
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4223
            if (stream)
4224
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4225
        } else if (!strcasecmp(cmd, "Qscale")) {
4226
            get_arg(arg, sizeof(arg), &p);
4227
            if (stream) {
4228
                video_enc.flags |= CODEC_FLAG_QSCALE;
4229
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4230
            }
4231
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4232
            get_arg(arg, sizeof(arg), &p);
4233
            if (stream) {
4234
                video_enc.max_qdiff = atoi(arg);
4235
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4236
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4237
                            filename, line_num);
4238
                    errors++;
4239
                }
4240
            }
4241
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4242
            get_arg(arg, sizeof(arg), &p);
4243
            if (stream) {
4244
                video_enc.qmax = atoi(arg);
4245
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4246
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4247
                            filename, line_num);
4248
                    errors++;
4249
                }
4250
            }
4251
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4252
            get_arg(arg, sizeof(arg), &p);
4253
            if (stream) {
4254
                video_enc.qmin = atoi(arg);
4255
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4256
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4257
                            filename, line_num);
4258
                    errors++;
4259
                }
4260
            }
4261
        } else if (!strcasecmp(cmd, "LumaElim")) {
4262
            get_arg(arg, sizeof(arg), &p);
4263
            if (stream)
4264
                video_enc.luma_elim_threshold = atoi(arg);
4265
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4266
            get_arg(arg, sizeof(arg), &p);
4267
            if (stream)
4268
                video_enc.chroma_elim_threshold = atoi(arg);
4269
        } else if (!strcasecmp(cmd, "LumiMask")) {
4270
            get_arg(arg, sizeof(arg), &p);
4271
            if (stream)
4272
                video_enc.lumi_masking = atof(arg);
4273
        } else if (!strcasecmp(cmd, "DarkMask")) {
4274
            get_arg(arg, sizeof(arg), &p);
4275
            if (stream)
4276
                video_enc.dark_masking = atof(arg);
4277
        } else if (!strcasecmp(cmd, "NoVideo")) {
4278
            video_id = CODEC_ID_NONE;
4279
        } else if (!strcasecmp(cmd, "NoAudio")) {
4280
            audio_id = CODEC_ID_NONE;
4281
        } else if (!strcasecmp(cmd, "ACL")) {
4282
            IPAddressACL acl;
4283

    
4284
            get_arg(arg, sizeof(arg), &p);
4285
            if (strcasecmp(arg, "allow") == 0)
4286
                acl.action = IP_ALLOW;
4287
            else if (strcasecmp(arg, "deny") == 0)
4288
                acl.action = IP_DENY;
4289
            else {
4290
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4291
                        filename, line_num, arg);
4292
                errors++;
4293
            }
4294

    
4295
            get_arg(arg, sizeof(arg), &p);
4296

    
4297
            if (resolve_host(&acl.first, arg) != 0) {
4298
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4299
                        filename, line_num, arg);
4300
                errors++;
4301
            } else
4302
                acl.last = acl.first;
4303

    
4304
            get_arg(arg, sizeof(arg), &p);
4305

    
4306
            if (arg[0]) {
4307
                if (resolve_host(&acl.last, arg) != 0) {
4308
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4309
                            filename, line_num, arg);
4310
                    errors++;
4311
                }
4312
            }
4313

    
4314
            if (!errors) {
4315
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4316
                IPAddressACL **naclp = 0;
4317

    
4318
                acl.next = 0;
4319
                *nacl = acl;
4320

    
4321
                if (stream)
4322
                    naclp = &stream->acl;
4323
                else if (feed)
4324
                    naclp = &feed->acl;
4325
                else {
4326
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4327
                            filename, line_num);
4328
                    errors++;
4329
                }
4330

    
4331
                if (naclp) {
4332
                    while (*naclp)
4333
                        naclp = &(*naclp)->next;
4334

    
4335
                    *naclp = nacl;
4336
                }
4337
            }
4338
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4339
            get_arg(arg, sizeof(arg), &p);
4340
            if (stream) {
4341
                av_freep(&stream->rtsp_option);
4342
                stream->rtsp_option = av_strdup(arg);
4343
            }
4344
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4345
            get_arg(arg, sizeof(arg), &p);
4346
            if (stream) {
4347
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4348
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4349
                            filename, line_num, arg);
4350
                    errors++;
4351
                }
4352
                stream->is_multicast = 1;
4353
                stream->loop = 1; /* default is looping */
4354
            }
4355
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4356
            get_arg(arg, sizeof(arg), &p);
4357
            if (stream)
4358
                stream->multicast_port = atoi(arg);
4359
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4360
            get_arg(arg, sizeof(arg), &p);
4361
            if (stream)
4362
                stream->multicast_ttl = atoi(arg);
4363
        } else if (!strcasecmp(cmd, "NoLoop")) {
4364
            if (stream)
4365
                stream->loop = 0;
4366
        } else if (!strcasecmp(cmd, "</Stream>")) {
4367
            if (!stream) {
4368
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4369
                        filename, line_num);
4370
                errors++;
4371
            } else {
4372
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4373
                    if (audio_id != CODEC_ID_NONE) {
4374
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4375
                        audio_enc.codec_id = audio_id;
4376
                        add_codec(stream, &audio_enc);
4377
                    }
4378
                    if (video_id != CODEC_ID_NONE) {
4379
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4380
                        video_enc.codec_id = video_id;
4381
                        add_codec(stream, &video_enc);
4382
                    }
4383
                }
4384
                stream = NULL;
4385
            }
4386
        } else if (!strcasecmp(cmd, "<Redirect")) {
4387
            /*********************************************/
4388
            char *q;
4389
            if (stream || feed || redirect) {
4390
                fprintf(stderr, "%s:%d: Already in a tag\n",
4391
                        filename, line_num);
4392
                errors++;
4393
            } else {
4394
                redirect = av_mallocz(sizeof(FFStream));
4395
                *last_stream = redirect;
4396
                last_stream = &redirect->next;
4397

    
4398
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4399
                q = strrchr(redirect->filename, '>');
4400
                if (*q)
4401
                    *q = '\0';
4402
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4403
            }
4404
        } else if (!strcasecmp(cmd, "URL")) {
4405
            if (redirect)
4406
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4407
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4408
            if (!redirect) {
4409
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4410
                        filename, line_num);
4411
                errors++;
4412
            } else {
4413
                if (!redirect->feed_filename[0]) {
4414
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4415
                            filename, line_num);
4416
                    errors++;
4417
                }
4418
                redirect = NULL;
4419
            }
4420
        } else if (!strcasecmp(cmd, "LoadModule")) {
4421
            get_arg(arg, sizeof(arg), &p);
4422
#if HAVE_DLOPEN
4423
            load_module(arg);
4424
#else
4425
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4426
                    filename, line_num, arg);
4427
            errors++;
4428
#endif
4429
        } else {
4430
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4431
                    filename, line_num, cmd);
4432
        }
4433
    }
4434

    
4435
    fclose(f);
4436
    if (errors)
4437
        return -1;
4438
    else
4439
        return 0;
4440
}
4441

    
4442
static void handle_child_exit(int sig)
4443
{
4444
    pid_t pid;
4445
    int status;
4446

    
4447
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4448
        FFStream *feed;
4449

    
4450
        for (feed = first_feed; feed; feed = feed->next) {
4451
            if (feed->pid == pid) {
4452
                int uptime = time(0) - feed->pid_start;
4453

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

    
4457
                if (uptime < 30)
4458
                    /* Turn off any more restarts */
4459
                    feed->child_argv = 0;
4460
            }
4461
        }
4462
    }
4463

    
4464
    need_to_start_children = 1;
4465
}
4466

    
4467
static void opt_debug(void)
4468
{
4469
    ffserver_debug = 1;
4470
    ffserver_daemon = 0;
4471
    logfilename[0] = '-';
4472
}
4473

    
4474
static void opt_show_help(void)
4475
{
4476
    printf("usage: ffserver [options]\n"
4477
           "Hyper fast multi format Audio/Video streaming server\n");
4478
    printf("\n");
4479
    show_help_options(options, "Main options:\n", 0, 0);
4480
}
4481

    
4482
static const OptionDef options[] = {
4483
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4484
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4485
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4486
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4487
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4488
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4489
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4490
    { NULL },
4491
};
4492

    
4493
int main(int argc, char **argv)
4494
{
4495
    struct sigaction sigact;
4496

    
4497
    av_register_all();
4498

    
4499
    show_banner();
4500

    
4501
    config_filename = "/etc/ffserver.conf";
4502

    
4503
    my_program_name = argv[0];
4504
    my_program_dir = getcwd(0, 0);
4505
    ffserver_daemon = 1;
4506

    
4507
    parse_options(argc, argv, options, NULL);
4508

    
4509
    unsetenv("http_proxy");             /* Kill the http_proxy */
4510

    
4511
    av_lfg_init(&random_state, ff_random_get_seed());
4512

    
4513
    memset(&sigact, 0, sizeof(sigact));
4514
    sigact.sa_handler = handle_child_exit;
4515
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4516
    sigaction(SIGCHLD, &sigact, 0);
4517

    
4518
    if (parse_ffconfig(config_filename) < 0) {
4519
        fprintf(stderr, "Incorrect config file - exiting.\n");
4520
        exit(1);
4521
    }
4522

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

    
4532
    build_file_streams();
4533

    
4534
    build_feed_streams();
4535

    
4536
    compute_bandwidth();
4537

    
4538
    /* put the process in background and detach it from its TTY */
4539
    if (ffserver_daemon) {
4540
        int pid;
4541

    
4542
        pid = fork();
4543
        if (pid < 0) {
4544
            perror("fork");
4545
            exit(1);
4546
        } else if (pid > 0) {
4547
            /* parent : exit */
4548
            exit(0);
4549
        } else {
4550
            /* child */
4551
            setsid();
4552
            close(0);
4553
            open("/dev/null", O_RDWR);
4554
            if (strcmp(logfilename, "-") != 0) {
4555
                close(1);
4556
                dup(0);
4557
            }
4558
            close(2);
4559
            dup(0);
4560
        }
4561
    }
4562

    
4563
    /* signal init */
4564
    signal(SIGPIPE, SIG_IGN);
4565

    
4566
    if (ffserver_daemon)
4567
        chdir("/");
4568

    
4569
    if (http_server() < 0) {
4570
        http_log("Could not start server\n");
4571
        exit(1);
4572
    }
4573

    
4574
    return 0;
4575
}