Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 8e2fd8e1

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, RTSPHeader *h);
277
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
278
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
279
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *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 already streaming this feed, do not let start another feeder. */
1359
    if (stream->feed_opened) {
1360
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1361
        http_log("feed %s already being received\n", stream->feed_filename);
1362
        goto send_error;
1363
    }
1364

    
1365
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1366
        current_bandwidth += stream->bandwidth;
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_strlcpy(c->fmt_ctx.author, c->stream->author,
2047
                   sizeof(c->fmt_ctx.author));
2048
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2049
                   sizeof(c->fmt_ctx.comment));
2050
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2051
                   sizeof(c->fmt_ctx.copyright));
2052
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2053
                   sizeof(c->fmt_ctx.title));
2054

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

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

    
2076
        c->got_key_frame = 0;
2077

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

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

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

    
2099
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2100
        c->buffer_ptr = c->pb_buffer;
2101
        c->buffer_end = c->pb_buffer + len;
2102

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

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

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

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

    
2237
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2238
                    c->cur_frame_bytes = len;
2239
                    c->buffer_ptr = c->pb_buffer;
2240
                    c->buffer_end = c->pb_buffer + len;
2241

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

    
2269
        c->last_packet_sent = 1;
2270
        break;
2271
    }
2272
    return 0;
2273
}
2274

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

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

    
2311
                c->data_count += len;
2312
                update_datarate(&c->datarate, c->data_count);
2313
                if (c->stream)
2314
                    c->stream->bytes_served += len;
2315

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

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

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

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

    
2397
static int http_start_receive_data(HTTPContext *c)
2398
{
2399
    int fd;
2400

    
2401
    if (c->stream->feed_opened)
2402
        return -1;
2403

    
2404
    /* Don't permit writing to this one */
2405
    if (c->stream->readonly)
2406
        return -1;
2407

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

    
2416
    c->stream->feed_write_index = ffm_read_write_index(fd);
2417
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2418
    lseek(fd, 0, SEEK_SET);
2419

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

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

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

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

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

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

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

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

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

    
2481
            /* write index */
2482
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2483

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

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

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

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

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

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

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

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

    
2549
/********************************************************************/
2550
/* RTSP handling */
2551

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

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

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

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

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

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

    
2627
    c->buffer_ptr[0] = '\0';
2628
    p = c->buffer;
2629

    
2630
    get_word(cmd, sizeof(cmd), &p);
2631
    get_word(url, sizeof(url), &p);
2632
    get_word(protocol, sizeof(protocol), &p);
2633

    
2634
    av_strlcpy(c->method, cmd, sizeof(c->method));
2635
    av_strlcpy(c->url, url, sizeof(c->url));
2636
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2637

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

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

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

    
2676
    /* handle sequence number */
2677
    c->seq = header->seq;
2678

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

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

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

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

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

    
2738
    return strlen(*pbuffer);
2739
}
2740

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2956

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

    
2960

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

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

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

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

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

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

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

    
3018
    rtp_c->state = HTTPSTATE_SEND_DATA;
3019

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

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

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

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

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

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

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

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

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

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

    
3075

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

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

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

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

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

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

    
3128
    current_bandwidth += stream->bandwidth;
3129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3561
        close(fd);
3562
    }
3563
}
3564

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

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

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

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

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

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

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

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

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

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

    
3682

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

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

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

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

    
3703
    return p->id;
3704
}
3705

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

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

    
3713
    return p->id;
3714
}
3715

    
3716
/* simplistic plugin support */
3717

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

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

    
3738
    init_func();
3739
}
3740
#endif
3741

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4424
static void handle_child_exit(int sig)
4425
{
4426
    pid_t pid;
4427
    int status;
4428

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

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

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

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

    
4446
    need_to_start_children = 1;
4447
}
4448

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

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

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

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

    
4479
    av_register_all();
4480

    
4481
    show_banner();
4482

    
4483
    config_filename = "/etc/ffserver.conf";
4484

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

    
4489
    parse_options(argc, argv, options, NULL);
4490

    
4491
    unsetenv("http_proxy");             /* Kill the http_proxy */
4492

    
4493
    av_random_init(&random_state, av_gettime() + (getpid() << 16));
4494

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

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

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

    
4514
    build_file_streams();
4515

    
4516
    build_feed_streams();
4517

    
4518
    compute_bandwidth();
4519

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

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

    
4545
    /* signal init */
4546
    signal(SIGPIPE, SIG_IGN);
4547

    
4548
    if (ffserver_daemon)
4549
        chdir("/");
4550

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

    
4556
    return 0;
4557
}