Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 5ee999b8

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/random.h"
39
#include "libavutil/intreadwrite.h"
40
#include "libavcodec/opt.h"
41
#include <stdarg.h>
42
#include <unistd.h>
43
#include <fcntl.h>
44
#include <sys/ioctl.h>
45
#if HAVE_POLL_H
46
#include <poll.h>
47
#endif
48
#include <errno.h>
49
#include <sys/time.h>
50
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
51
#include <time.h>
52
#include <sys/wait.h>
53
#include <signal.h>
54
#if HAVE_DLFCN_H
55
#include <dlfcn.h>
56
#endif
57

    
58
#include "cmdutils.h"
59

    
60
#undef exit
61

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

    
65
static const OptionDef options[];
66

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

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

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

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

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

    
98
#define IOBUFFER_INIT_SIZE 8192
99

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

    
104
#define SYNC_TIMEOUT (10 * 1000)
105

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
312
static AVRandomState random_state;
313

    
314
static FILE *logfile = NULL;
315

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

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

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

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

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

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

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

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

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

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

    
397

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

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

    
407
            feed->pid = fork();
408

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

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

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

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

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

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

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

    
450
                signal(SIGPIPE, SIG_DFL);
451

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

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

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

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

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

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

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

    
489
    return server_fd;
490
}
491

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
579
    start_children(first_feed);
580

    
581
    start_multicast();
582

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

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

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

    
655
        cur_time = av_gettime() / 1000;
656

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

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

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

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

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

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

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

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

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

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

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

    
739
    start_wait_request(c, is_rtsp);
740

    
741
    return;
742

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

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

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

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

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

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

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

    
804
    ctx = &c->fmt_ctx;
805

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1028
                q += 20;
1029

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

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

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

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

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

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

    
1054
        p++;
1055
    }
1056

    
1057
    return 0;
1058
}
1059

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

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

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

    
1075
        /* Potential stream */
1076

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

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

    
1094
    return best;
1095
}
1096

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

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

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

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

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

    
1132
    return action_required;
1133
}
1134

    
1135

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1289
        p++;
1290
    }
1291

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

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

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

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

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

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

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

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

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

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

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

    
1399
            p++;
1400
        }
1401

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

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

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

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

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

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

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

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

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

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

    
1507
    stream->conns_served++;
1508

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

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

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

    
1530
                p++;
1531
            }
1532

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

    
1536
                logline += 17;
1537

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

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

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

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

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

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

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

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

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

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

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

    
1602
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1603

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1810
                parameters[0] = 0;
1811

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2036

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

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

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

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

    
2072
        c->got_key_frame = 0;
2073

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2551
/********************************************************************/
2552
/* RTSP handling */
2553

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2737
    return strlen(*pbuffer);
2738
}
2739

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2955

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

    
2959

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

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

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

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

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

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

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

    
3017
    rtp_c->state = HTTPSTATE_SEND_DATA;
3018

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

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

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

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

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

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

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

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

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

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

    
3074

    
3075
/********************************************************************/
3076
/* RTP handling */
3077

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

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

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

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

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

    
3127
    current_bandwidth += stream->bandwidth;
3128

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3237
/********************************************************************/
3238
/* ffserver initialization */
3239

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3560
        close(fd);
3561
    }
3562
}
3563

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

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

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

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

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

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

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

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

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

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

    
3681

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

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

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

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

    
3702
    return p->id;
3703
}
3704

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

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

    
3712
    return p->id;
3713
}
3714

    
3715
/* simplistic plugin support */
3716

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

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

    
3737
    init_func();
3738
}
3739
#endif
3740

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

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

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

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

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

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

    
3875
                get_arg(feed->filename, sizeof(feed->filename), &p);
3876
                q = strrchr(feed->filename, '>');
3877
                if (*q)
3878
                    *q = '\0';
3879
                feed->fmt = guess_format("ffm", NULL, NULL);
3880
                /* defaut feed file */
3881
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3882
                         "/tmp/%s.ffm", feed->filename);
3883
                feed->feed_max_size = 5 * 1024 * 1024;
3884
                feed->is_feed = 1;
3885
                feed->feed = feed; /* self feeding :-) */
3886
            }
3887
        } else if (!strcasecmp(cmd, "Launch")) {
3888
            if (feed) {
3889
                int i;
3890

    
3891
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3892

    
3893
                for (i = 0; i < 62; i++) {
3894
                    get_arg(arg, sizeof(arg), &p);
3895
                    if (!arg[0])
3896
                        break;
3897

    
3898
                    feed->child_argv[i] = av_strdup(arg);
3899
                }
3900

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

    
3903
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3904
                    "http://%s:%d/%s",
3905
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3906
                    inet_ntoa(my_http_addr.sin_addr),
3907
                    ntohs(my_http_addr.sin_port), feed->filename);
3908
            }
3909
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3910
            if (feed) {
3911
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3912
                feed->readonly = 1;
3913
            } else if (stream) {
3914
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3915
            }
3916
        } else if (!strcasecmp(cmd, "File")) {
3917
            if (feed) {
3918
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3919
            } else if (stream)
3920
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3921
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3922
            if (feed) {
3923
                char *p1;
3924
                double fsize;
3925

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

    
3962
                get_arg(stream->filename, sizeof(stream->filename), &p);
3963
                q = strrchr(stream->filename, '>');
3964
                if (*q)
3965
                    *q = '\0';
3966
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3967
                /* fetch avclass so AVOption works
3968
                 * FIXME try to use avcodec_get_context_defaults2
3969
                 * without changing defaults too much */
3970
                avcodec_get_context_defaults(&video_enc);
3971
                class = video_enc.av_class;
3972
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3973
                memset(&video_enc, 0, sizeof(AVCodecContext));
3974
                audio_enc.av_class = class;
3975
                video_enc.av_class = class;
3976
                audio_id = CODEC_ID_NONE;
3977
                video_id = CODEC_ID_NONE;
3978
                if (stream->fmt) {
3979
                    audio_id = stream->fmt->audio_codec;
3980
                    video_id = stream->fmt->video_codec;
3981
                }
3982
            }
3983
        } else if (!strcasecmp(cmd, "Feed")) {
3984
            get_arg(arg, sizeof(arg), &p);
3985
            if (stream) {
3986
                FFStream *sfeed;
3987

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

    
4100
                get_arg(arg, sizeof(arg), &p);
4101

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

    
4264
            get_arg(arg, sizeof(arg), &p);
4265
            if (strcasecmp(arg, "allow") == 0)
4266
                acl.action = IP_ALLOW;
4267
            else if (strcasecmp(arg, "deny") == 0)
4268
                acl.action = IP_DENY;
4269
            else {
4270
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4271
                        filename, line_num, arg);
4272
                errors++;
4273
            }
4274

    
4275
            get_arg(arg, sizeof(arg), &p);
4276

    
4277
            if (resolve_host(&acl.first, arg) != 0) {
4278
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4279
                        filename, line_num, arg);
4280
                errors++;
4281
            } else
4282
                acl.last = acl.first;
4283

    
4284
            get_arg(arg, sizeof(arg), &p);
4285

    
4286
            if (arg[0]) {
4287
                if (resolve_host(&acl.last, arg) != 0) {
4288
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4289
                            filename, line_num, arg);
4290
                    errors++;
4291
                }
4292
            }
4293

    
4294
            if (!errors) {
4295
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4296
                IPAddressACL **naclp = 0;
4297

    
4298
                acl.next = 0;
4299
                *nacl = acl;
4300

    
4301
                if (stream)
4302
                    naclp = &stream->acl;
4303
                else if (feed)
4304
                    naclp = &feed->acl;
4305
                else {
4306
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4307
                            filename, line_num);
4308
                    errors++;
4309
                }
4310

    
4311
                if (naclp) {
4312
                    while (*naclp)
4313
                        naclp = &(*naclp)->next;
4314

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

    
4378
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4379
                q = strrchr(redirect->filename, '>');
4380
                if (*q)
4381
                    *q = '\0';
4382
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4383
            }
4384
        } else if (!strcasecmp(cmd, "URL")) {
4385
            if (redirect)
4386
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4387
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4388
            if (!redirect) {
4389
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4390
                        filename, line_num);
4391
                errors++;
4392
            } else {
4393
                if (!redirect->feed_filename[0]) {
4394
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4395
                            filename, line_num);
4396
                    errors++;
4397
                }
4398
                redirect = NULL;
4399
            }
4400
        } else if (!strcasecmp(cmd, "LoadModule")) {
4401
            get_arg(arg, sizeof(arg), &p);
4402
#if HAVE_DLOPEN
4403
            load_module(arg);
4404
#else
4405
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4406
                    filename, line_num, arg);
4407
            errors++;
4408
#endif
4409
        } else {
4410
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4411
                    filename, line_num, cmd);
4412
        }
4413
    }
4414

    
4415
    fclose(f);
4416
    if (errors)
4417
        return -1;
4418
    else
4419
        return 0;
4420
}
4421

    
4422
static void handle_child_exit(int sig)
4423
{
4424
    pid_t pid;
4425
    int status;
4426

    
4427
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4428
        FFStream *feed;
4429

    
4430
        for (feed = first_feed; feed; feed = feed->next) {
4431
            if (feed->pid == pid) {
4432
                int uptime = time(0) - feed->pid_start;
4433

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

    
4437
                if (uptime < 30)
4438
                    /* Turn off any more restarts */
4439
                    feed->child_argv = 0;
4440
            }
4441
        }
4442
    }
4443

    
4444
    need_to_start_children = 1;
4445
}
4446

    
4447
static void opt_debug(void)
4448
{
4449
    ffserver_debug = 1;
4450
    ffserver_daemon = 0;
4451
    logfilename[0] = '-';
4452
}
4453

    
4454
static void opt_show_help(void)
4455
{
4456
    printf("usage: ffserver [options]\n"
4457
           "Hyper fast multi format Audio/Video streaming server\n");
4458
    printf("\n");
4459
    show_help_options(options, "Main options:\n", 0, 0);
4460
}
4461

    
4462
static const OptionDef options[] = {
4463
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4464
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4465
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4466
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4467
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4468
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4469
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4470
    { NULL },
4471
};
4472

    
4473
int main(int argc, char **argv)
4474
{
4475
    struct sigaction sigact;
4476

    
4477
    av_register_all();
4478

    
4479
    show_banner();
4480

    
4481
    config_filename = "/etc/ffserver.conf";
4482

    
4483
    my_program_name = argv[0];
4484
    my_program_dir = getcwd(0, 0);
4485
    ffserver_daemon = 1;
4486

    
4487
    parse_options(argc, argv, options, NULL);
4488

    
4489
    unsetenv("http_proxy");             /* Kill the http_proxy */
4490

    
4491
    av_random_init(&random_state, av_gettime() + (getpid() << 16));
4492

    
4493
    memset(&sigact, 0, sizeof(sigact));
4494
    sigact.sa_handler = handle_child_exit;
4495
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4496
    sigaction(SIGCHLD, &sigact, 0);
4497

    
4498
    if (parse_ffconfig(config_filename) < 0) {
4499
        fprintf(stderr, "Incorrect config file - exiting.\n");
4500
        exit(1);
4501
    }
4502

    
4503
    /* open log file if needed */
4504
    if (logfilename[0] != '\0') {
4505
        if (!strcmp(logfilename, "-"))
4506
            logfile = stdout;
4507
        else
4508
            logfile = fopen(logfilename, "a");
4509
        av_log_set_callback(http_av_log);
4510
    }
4511

    
4512
    build_file_streams();
4513

    
4514
    build_feed_streams();
4515

    
4516
    compute_bandwidth();
4517

    
4518
    /* put the process in background and detach it from its TTY */
4519
    if (ffserver_daemon) {
4520
        int pid;
4521

    
4522
        pid = fork();
4523
        if (pid < 0) {
4524
            perror("fork");
4525
            exit(1);
4526
        } else if (pid > 0) {
4527
            /* parent : exit */
4528
            exit(0);
4529
        } else {
4530
            /* child */
4531
            setsid();
4532
            close(0);
4533
            open("/dev/null", O_RDWR);
4534
            if (strcmp(logfilename, "-") != 0) {
4535
                close(1);
4536
                dup(0);
4537
            }
4538
            close(2);
4539
            dup(0);
4540
        }
4541
    }
4542

    
4543
    /* signal init */
4544
    signal(SIGPIPE, SIG_IGN);
4545

    
4546
    if (ffserver_daemon)
4547
        chdir("/");
4548

    
4549
    if (http_server() < 0) {
4550
        http_log("Could not start server\n");
4551
        exit(1);
4552
    }
4553

    
4554
    return 0;
4555
}