Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 20f93c3c

History | View | Annotate | Download (151 KB)

1
/*
2
 * Multiple format streaming server
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

    
22
#define _XOPEN_SOURCE 600
23

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

    
59
#include "cmdutils.h"
60

    
61
#undef exit
62

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

    
66
static const OptionDef options[];
67

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

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

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

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

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

    
99
#define IOBUFFER_INIT_SIZE 8192
100

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

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

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

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

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

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

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

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

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

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

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

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

    
398

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

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

    
408
            feed->pid = fork();
409

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

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

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

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

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

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

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

    
451
                signal(SIGPIPE, SIG_DFL);
452

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

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

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

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

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

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

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

    
490
    return server_fd;
491
}
492

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
580
    start_children(first_feed);
581

    
582
    start_multicast();
583

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

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

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

    
656
        cur_time = av_gettime() / 1000;
657

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

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

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

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

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

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

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

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

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

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

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

    
740
    start_wait_request(c, is_rtsp);
741

    
742
    return;
743

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

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

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

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

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

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

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

    
805
    ctx = &c->fmt_ctx;
806

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1029
                q += 20;
1030

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

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

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

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

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

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

    
1055
        p++;
1056
    }
1057

    
1058
    return 0;
1059
}
1060

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

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

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

    
1076
        /* Potential stream */
1077

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

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

    
1095
    return best;
1096
}
1097

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

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

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

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

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

    
1133
    return action_required;
1134
}
1135

    
1136

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1266
    if (ffserver_debug)
1267
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1268

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

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

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

    
1290
        p++;
1291
    }
1292

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

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

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

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

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

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

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

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

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

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

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

    
1401
            p++;
1402
        }
1403

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

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

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

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

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

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

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

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

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

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

    
1509
    stream->conns_served++;
1510

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

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

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

    
1532
                p++;
1533
            }
1534

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

    
1538
                logline += 17;
1539

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1812
                parameters[0] = 0;
1813

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1995
    /* open each parser */
1996
    for(i=0;i<s->nb_streams;i++)
1997
        open_parser(s, i);
1998

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

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

    
2019
/* return the server clock (in us) */
2020
static int64_t get_server_clock(HTTPContext *c)
2021
{
2022
    /* compute current pts value from system time */
2023
    return (cur_time - c->start_time) * 1000;
2024
}
2025

    
2026
/* return the estimated time at which the current packet must be sent
2027
   (in us) */
2028
static int64_t get_packet_send_clock(HTTPContext *c)
2029
{
2030
    int bytes_left, bytes_sent, frame_bytes;
2031

    
2032
    frame_bytes = c->cur_frame_bytes;
2033
    if (frame_bytes <= 0)
2034
        return c->cur_pts;
2035
    else {
2036
        bytes_left = c->buffer_end - c->buffer_ptr;
2037
        bytes_sent = frame_bytes - bytes_left;
2038
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2039
    }
2040
}
2041

    
2042

    
2043
static int http_prepare_data(HTTPContext *c)
2044
{
2045
    int i, len, ret;
2046
    AVFormatContext *ctx;
2047

    
2048
    av_freep(&c->pb_buffer);
2049
    switch(c->state) {
2050
    case HTTPSTATE_SEND_DATA_HEADER:
2051
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2052
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2053
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2054
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2055
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2056

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

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

    
2078
        c->got_key_frame = 0;
2079

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

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

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

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

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

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

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

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

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

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

    
2271
        c->last_packet_sent = 1;
2272
        break;
2273
    }
2274
    return 0;
2275
}
2276

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

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

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

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

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

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

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

    
2399
static int http_start_receive_data(HTTPContext *c)
2400
{
2401
    int fd;
2402

    
2403
    if (c->stream->feed_opened)
2404
        return -1;
2405

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

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

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

    
2425
    /* init buffer input */
2426
    c->buffer_ptr = c->buffer;
2427
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2428
    c->stream->feed_opened = 1;
2429
    return 0;
2430
}
2431

    
2432
static int http_receive_data(HTTPContext *c)
2433
{
2434
    HTTPContext *c1;
2435

    
2436
    if (c->buffer_end > c->buffer_ptr) {
2437
        int len;
2438

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

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

    
2463
    if (c->buffer_ptr >= c->buffer_end) {
2464
        FFStream *feed = c->stream;
2465
        /* a packet has been received : write it in the store, except
2466
           if header */
2467
        if (c->data_count > FFM_PACKET_SIZE) {
2468

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

    
2477
            feed->feed_write_index += FFM_PACKET_SIZE;
2478
            /* update file size */
2479
            if (feed->feed_write_index > c->stream->feed_size)
2480
                feed->feed_size = feed->feed_write_index;
2481

    
2482
            /* handle wrap around if max file size reached */
2483
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2484
                feed->feed_write_index = FFM_PACKET_SIZE;
2485

    
2486
            /* write index */
2487
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2488
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2489
                goto fail;
2490
            }
2491

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

    
2505
            /* use feed output format name to find corresponding input format */
2506
            fmt_in = av_find_input_format(feed->fmt->name);
2507
            if (!fmt_in)
2508
                goto fail;
2509

    
2510
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2511
            pb->is_streamed = 1;
2512

    
2513
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2514
                av_free(pb);
2515
                goto fail;
2516
            }
2517

    
2518
            /* Now we have the actual streams */
2519
            if (s->nb_streams != feed->nb_streams) {
2520
                av_close_input_stream(s);
2521
                av_free(pb);
2522
                http_log("Feed '%s' stream number does not match registered feed\n",
2523
                         c->stream->feed_filename);
2524
                goto fail;
2525
            }
2526

    
2527
            for (i = 0; i < s->nb_streams; i++) {
2528
                AVStream *fst = feed->streams[i];
2529
                AVStream *st = s->streams[i];
2530
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2531
                if (fst->codec->extradata_size) {
2532
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2533
                    if (!fst->codec->extradata)
2534
                        goto fail;
2535
                    memcpy(fst->codec->extradata, st->codec->extradata,
2536
                           fst->codec->extradata_size);
2537
                }
2538
            }
2539

    
2540
            av_close_input_stream(s);
2541
            av_free(pb);
2542
        }
2543
        c->buffer_ptr = c->buffer;
2544
    }
2545

    
2546
    return 0;
2547
 fail:
2548
    c->stream->feed_opened = 0;
2549
    close(c->feed_fd);
2550
    /* wake up any waiting connections to stop waiting for feed */
2551
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2552
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2553
            c1->stream->feed == c->stream->feed)
2554
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2555
    }
2556
    return -1;
2557
}
2558

    
2559
/********************************************************************/
2560
/* RTSP handling */
2561

    
2562
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2563
{
2564
    const char *str;
2565
    time_t ti;
2566
    char *p;
2567
    char buf2[32];
2568

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

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

    
2611
    /* output GMT time */
2612
    ti = time(NULL);
2613
    p = ctime(&ti);
2614
    strcpy(buf2, p);
2615
    p = buf2 + strlen(p) - 1;
2616
    if (*p == '\n')
2617
        *p = '\0';
2618
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2619
}
2620

    
2621
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2622
{
2623
    rtsp_reply_header(c, error_number);
2624
    url_fprintf(c->pb, "\r\n");
2625
}
2626

    
2627
static int rtsp_parse_request(HTTPContext *c)
2628
{
2629
    const char *p, *p1, *p2;
2630
    char cmd[32];
2631
    char url[1024];
2632
    char protocol[32];
2633
    char line[1024];
2634
    int len;
2635
    RTSPMessageHeader header1, *header = &header1;
2636

    
2637
    c->buffer_ptr[0] = '\0';
2638
    p = c->buffer;
2639

    
2640
    get_word(cmd, sizeof(cmd), &p);
2641
    get_word(url, sizeof(url), &p);
2642
    get_word(protocol, sizeof(protocol), &p);
2643

    
2644
    av_strlcpy(c->method, cmd, sizeof(c->method));
2645
    av_strlcpy(c->url, url, sizeof(c->url));
2646
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2647

    
2648
    if (url_open_dyn_buf(&c->pb) < 0) {
2649
        /* XXX: cannot do more */
2650
        c->pb = NULL; /* safety */
2651
        return -1;
2652
    }
2653

    
2654
    /* check version name */
2655
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2656
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2657
        goto the_end;
2658
    }
2659

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

    
2686
    /* handle sequence number */
2687
    c->seq = header->seq;
2688

    
2689
    if (!strcmp(cmd, "DESCRIBE"))
2690
        rtsp_cmd_describe(c, url);
2691
    else if (!strcmp(cmd, "OPTIONS"))
2692
        rtsp_cmd_options(c, url);
2693
    else if (!strcmp(cmd, "SETUP"))
2694
        rtsp_cmd_setup(c, url, header);
2695
    else if (!strcmp(cmd, "PLAY"))
2696
        rtsp_cmd_play(c, url, header);
2697
    else if (!strcmp(cmd, "PAUSE"))
2698
        rtsp_cmd_pause(c, url, header);
2699
    else if (!strcmp(cmd, "TEARDOWN"))
2700
        rtsp_cmd_teardown(c, url, header);
2701
    else
2702
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2703

    
2704
 the_end:
2705
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2706
    c->pb = NULL; /* safety */
2707
    if (len < 0) {
2708
        /* XXX: cannot do more */
2709
        return -1;
2710
    }
2711
    c->buffer_ptr = c->pb_buffer;
2712
    c->buffer_end = c->pb_buffer + len;
2713
    c->state = RTSPSTATE_SEND_REPLY;
2714
    return 0;
2715
}
2716

    
2717
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2718
                                   struct in_addr my_ip)
2719
{
2720
    AVFormatContext *avc;
2721
    AVStream avs[MAX_STREAMS];
2722
    int i;
2723

    
2724
    avc =  avformat_alloc_context();
2725
    if (avc == NULL) {
2726
        return -1;
2727
    }
2728
    av_metadata_set(&avc->metadata, "title",
2729
                    stream->title[0] ? stream->title : "No Title");
2730
    avc->nb_streams = stream->nb_streams;
2731
    if (stream->is_multicast) {
2732
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2733
                 inet_ntoa(stream->multicast_ip),
2734
                 stream->multicast_port, stream->multicast_ttl);
2735
    }
2736

    
2737
    for(i = 0; i < stream->nb_streams; i++) {
2738
        avc->streams[i] = &avs[i];
2739
        avc->streams[i]->codec = stream->streams[i]->codec;
2740
    }
2741
    *pbuffer = av_mallocz(2048);
2742
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2743
    av_free(avc);
2744

    
2745
    return strlen(*pbuffer);
2746
}
2747

    
2748
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2749
{
2750
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2751
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2752
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2753
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2754
    url_fprintf(c->pb, "\r\n");
2755
}
2756

    
2757
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2758
{
2759
    FFStream *stream;
2760
    char path1[1024];
2761
    const char *path;
2762
    uint8_t *content;
2763
    int content_length, len;
2764
    struct sockaddr_in my_addr;
2765

    
2766
    /* find which url is asked */
2767
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2768
    path = path1;
2769
    if (*path == '/')
2770
        path++;
2771

    
2772
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2773
        if (!stream->is_feed &&
2774
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2775
            !strcmp(path, stream->filename)) {
2776
            goto found;
2777
        }
2778
    }
2779
    /* no stream found */
2780
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2781
    return;
2782

    
2783
 found:
2784
    /* prepare the media description in sdp format */
2785

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

    
2801
static HTTPContext *find_rtp_session(const char *session_id)
2802
{
2803
    HTTPContext *c;
2804

    
2805
    if (session_id[0] == '\0')
2806
        return NULL;
2807

    
2808
    for(c = first_http_ctx; c != NULL; c = c->next) {
2809
        if (!strcmp(c->session_id, session_id))
2810
            return c;
2811
    }
2812
    return NULL;
2813
}
2814

    
2815
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2816
{
2817
    RTSPTransportField *th;
2818
    int i;
2819

    
2820
    for(i=0;i<h->nb_transports;i++) {
2821
        th = &h->transports[i];
2822
        if (th->lower_transport == lower_transport)
2823
            return th;
2824
    }
2825
    return NULL;
2826
}
2827

    
2828
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2829
                           RTSPMessageHeader *h)
2830
{
2831
    FFStream *stream;
2832
    int stream_index, port;
2833
    char buf[1024];
2834
    char path1[1024];
2835
    const char *path;
2836
    HTTPContext *rtp_c;
2837
    RTSPTransportField *th;
2838
    struct sockaddr_in dest_addr;
2839
    RTSPActionServerSetup setup;
2840

    
2841
    /* find which url is asked */
2842
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2843
    path = path1;
2844
    if (*path == '/')
2845
        path++;
2846

    
2847
    /* now check each stream */
2848
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2849
        if (!stream->is_feed &&
2850
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2851
            /* accept aggregate filenames only if single stream */
2852
            if (!strcmp(path, stream->filename)) {
2853
                if (stream->nb_streams != 1) {
2854
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2855
                    return;
2856
                }
2857
                stream_index = 0;
2858
                goto found;
2859
            }
2860

    
2861
            for(stream_index = 0; stream_index < stream->nb_streams;
2862
                stream_index++) {
2863
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2864
                         stream->filename, stream_index);
2865
                if (!strcmp(path, buf))
2866
                    goto found;
2867
            }
2868
        }
2869
    }
2870
    /* no stream found */
2871
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2872
    return;
2873
 found:
2874

    
2875
    /* generate session id if needed */
2876
    if (h->session_id[0] == '\0')
2877
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2878
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2879

    
2880
    /* find rtp session, and create it if none found */
2881
    rtp_c = find_rtp_session(h->session_id);
2882
    if (!rtp_c) {
2883
        /* always prefer UDP */
2884
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2885
        if (!th) {
2886
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2887
            if (!th) {
2888
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2889
                return;
2890
            }
2891
        }
2892

    
2893
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2894
                                   th->lower_transport);
2895
        if (!rtp_c) {
2896
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2897
            return;
2898
        }
2899

    
2900
        /* open input stream */
2901
        if (open_input_stream(rtp_c, "") < 0) {
2902
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2903
            return;
2904
        }
2905
    }
2906

    
2907
    /* test if stream is OK (test needed because several SETUP needs
2908
       to be done for a given file) */
2909
    if (rtp_c->stream != stream) {
2910
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2911
        return;
2912
    }
2913

    
2914
    /* test if stream is already set up */
2915
    if (rtp_c->rtp_ctx[stream_index]) {
2916
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2917
        return;
2918
    }
2919

    
2920
    /* check transport */
2921
    th = find_transport(h, rtp_c->rtp_protocol);
2922
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2923
                th->client_port_min <= 0)) {
2924
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2925
        return;
2926
    }
2927

    
2928
    /* setup default options */
2929
    setup.transport_option[0] = '\0';
2930
    dest_addr = rtp_c->from_addr;
2931
    dest_addr.sin_port = htons(th->client_port_min);
2932

    
2933
    /* setup stream */
2934
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2935
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2936
        return;
2937
    }
2938

    
2939
    /* now everything is OK, so we can send the connection parameters */
2940
    rtsp_reply_header(c, RTSP_STATUS_OK);
2941
    /* session ID */
2942
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2943

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

    
2963

    
2964
    url_fprintf(c->pb, "\r\n");
2965
}
2966

    
2967

    
2968
/* find an rtp connection by using the session ID. Check consistency
2969
   with filename */
2970
static HTTPContext *find_rtp_session_with_url(const char *url,
2971
                                              const char *session_id)
2972
{
2973
    HTTPContext *rtp_c;
2974
    char path1[1024];
2975
    const char *path;
2976
    char buf[1024];
2977
    int s;
2978

    
2979
    rtp_c = find_rtp_session(session_id);
2980
    if (!rtp_c)
2981
        return NULL;
2982

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

    
3000
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3001
{
3002
    HTTPContext *rtp_c;
3003

    
3004
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3005
    if (!rtp_c) {
3006
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3007
        return;
3008
    }
3009

    
3010
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3011
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3012
        rtp_c->state != HTTPSTATE_READY) {
3013
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3014
        return;
3015
    }
3016

    
3017
#if 0
3018
    /* XXX: seek in stream */
3019
    if (h->range_start != AV_NOPTS_VALUE) {
3020
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3021
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3022
    }
3023
#endif
3024

    
3025
    rtp_c->state = HTTPSTATE_SEND_DATA;
3026

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

    
3034
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3035
{
3036
    HTTPContext *rtp_c;
3037

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

    
3044
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3045
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3046
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3047
        return;
3048
    }
3049

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

    
3059
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3060
{
3061
    HTTPContext *rtp_c;
3062
    char session_id[32];
3063

    
3064
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3065
    if (!rtp_c) {
3066
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3067
        return;
3068
    }
3069

    
3070
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3071

    
3072
    /* abort the session */
3073
    close_connection(rtp_c);
3074

    
3075
    /* now everything is OK, so we can send the connection parameters */
3076
    rtsp_reply_header(c, RTSP_STATUS_OK);
3077
    /* session ID */
3078
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3079
    url_fprintf(c->pb, "\r\n");
3080
}
3081

    
3082

    
3083
/********************************************************************/
3084
/* RTP handling */
3085

    
3086
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3087
                                       FFStream *stream, const char *session_id,
3088
                                       enum RTSPLowerTransport rtp_protocol)
3089
{
3090
    HTTPContext *c = NULL;
3091
    const char *proto_str;
3092

    
3093
    /* XXX: should output a warning page when coming
3094
       close to the connection limit */
3095
    if (nb_connections >= nb_max_connections)
3096
        goto fail;
3097

    
3098
    /* add a new connection */
3099
    c = av_mallocz(sizeof(HTTPContext));
3100
    if (!c)
3101
        goto fail;
3102

    
3103
    c->fd = -1;
3104
    c->poll_entry = NULL;
3105
    c->from_addr = *from_addr;
3106
    c->buffer_size = IOBUFFER_INIT_SIZE;
3107
    c->buffer = av_malloc(c->buffer_size);
3108
    if (!c->buffer)
3109
        goto fail;
3110
    nb_connections++;
3111
    c->stream = stream;
3112
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3113
    c->state = HTTPSTATE_READY;
3114
    c->is_packetized = 1;
3115
    c->rtp_protocol = rtp_protocol;
3116

    
3117
    /* protocol is shown in statistics */
3118
    switch(c->rtp_protocol) {
3119
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3120
        proto_str = "MCAST";
3121
        break;
3122
    case RTSP_LOWER_TRANSPORT_UDP:
3123
        proto_str = "UDP";
3124
        break;
3125
    case RTSP_LOWER_TRANSPORT_TCP:
3126
        proto_str = "TCP";
3127
        break;
3128
    default:
3129
        proto_str = "???";
3130
        break;
3131
    }
3132
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3133
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3134

    
3135
    current_bandwidth += stream->bandwidth;
3136

    
3137
    c->next = first_http_ctx;
3138
    first_http_ctx = c;
3139
    return c;
3140

    
3141
 fail:
3142
    if (c) {
3143
        av_free(c->buffer);
3144
        av_free(c);
3145
    }
3146
    return NULL;
3147
}
3148

    
3149
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3150
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3151
   used. */
3152
static int rtp_new_av_stream(HTTPContext *c,
3153
                             int stream_index, struct sockaddr_in *dest_addr,
3154
                             HTTPContext *rtsp_c)
3155
{
3156
    AVFormatContext *ctx;
3157
    AVStream *st;
3158
    char *ipaddr;
3159
    URLContext *h = NULL;
3160
    uint8_t *dummy_buf;
3161
    int max_packet_size;
3162

    
3163
    /* now we can open the relevant output stream */
3164
    ctx = avformat_alloc_context();
3165
    if (!ctx)
3166
        return -1;
3167
    ctx->oformat = guess_format("rtp", NULL, NULL);
3168

    
3169
    st = av_mallocz(sizeof(AVStream));
3170
    if (!st)
3171
        goto fail;
3172
    st->codec= avcodec_alloc_context();
3173
    ctx->nb_streams = 1;
3174
    ctx->streams[0] = st;
3175

    
3176
    if (!c->stream->feed ||
3177
        c->stream->feed == c->stream)
3178
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3179
    else
3180
        memcpy(st,
3181
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3182
               sizeof(AVStream));
3183
    st->priv_data = NULL;
3184

    
3185
    /* build destination RTP address */
3186
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3187

    
3188
    switch(c->rtp_protocol) {
3189
    case RTSP_LOWER_TRANSPORT_UDP:
3190
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3191
        /* RTP/UDP case */
3192

    
3193
        /* XXX: also pass as parameter to function ? */
3194
        if (c->stream->is_multicast) {
3195
            int ttl;
3196
            ttl = c->stream->multicast_ttl;
3197
            if (!ttl)
3198
                ttl = 16;
3199
            snprintf(ctx->filename, sizeof(ctx->filename),
3200
                     "rtp://%s:%d?multicast=1&ttl=%d",
3201
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3202
        } else {
3203
            snprintf(ctx->filename, sizeof(ctx->filename),
3204
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3205
        }
3206

    
3207
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3208
            goto fail;
3209
        c->rtp_handles[stream_index] = h;
3210
        max_packet_size = url_get_max_packet_size(h);
3211
        break;
3212
    case RTSP_LOWER_TRANSPORT_TCP:
3213
        /* RTP/TCP case */
3214
        c->rtsp_c = rtsp_c;
3215
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3216
        break;
3217
    default:
3218
        goto fail;
3219
    }
3220

    
3221
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3222
             ipaddr, ntohs(dest_addr->sin_port),
3223
             c->stream->filename, stream_index, c->protocol);
3224

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

    
3241
    c->rtp_ctx[stream_index] = ctx;
3242
    return 0;
3243
}
3244

    
3245
/********************************************************************/
3246
/* ffserver initialization */
3247

    
3248
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3249
{
3250
    AVStream *fst;
3251

    
3252
    fst = av_mallocz(sizeof(AVStream));
3253
    if (!fst)
3254
        return NULL;
3255
    fst->codec= avcodec_alloc_context();
3256
    fst->priv_data = av_mallocz(sizeof(FeedData));
3257
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3258
    fst->index = stream->nb_streams;
3259
    av_set_pts_info(fst, 33, 1, 90000);
3260
    stream->streams[stream->nb_streams++] = fst;
3261
    return fst;
3262
}
3263

    
3264
/* return the stream number in the feed */
3265
static int add_av_stream(FFStream *feed, AVStream *st)
3266
{
3267
    AVStream *fst;
3268
    AVCodecContext *av, *av1;
3269
    int i;
3270

    
3271
    av = st->codec;
3272
    for(i=0;i<feed->nb_streams;i++) {
3273
        st = feed->streams[i];
3274
        av1 = st->codec;
3275
        if (av1->codec_id == av->codec_id &&
3276
            av1->codec_type == av->codec_type &&
3277
            av1->bit_rate == av->bit_rate) {
3278

    
3279
            switch(av->codec_type) {
3280
            case CODEC_TYPE_AUDIO:
3281
                if (av1->channels == av->channels &&
3282
                    av1->sample_rate == av->sample_rate)
3283
                    goto found;
3284
                break;
3285
            case CODEC_TYPE_VIDEO:
3286
                if (av1->width == av->width &&
3287
                    av1->height == av->height &&
3288
                    av1->time_base.den == av->time_base.den &&
3289
                    av1->time_base.num == av->time_base.num &&
3290
                    av1->gop_size == av->gop_size)
3291
                    goto found;
3292
                break;
3293
            default:
3294
                abort();
3295
            }
3296
        }
3297
    }
3298

    
3299
    fst = add_av_stream1(feed, av);
3300
    if (!fst)
3301
        return -1;
3302
    return feed->nb_streams - 1;
3303
 found:
3304
    return i;
3305
}
3306

    
3307
static void remove_stream(FFStream *stream)
3308
{
3309
    FFStream **ps;
3310
    ps = &first_stream;
3311
    while (*ps != NULL) {
3312
        if (*ps == stream)
3313
            *ps = (*ps)->next;
3314
        else
3315
            ps = &(*ps)->next;
3316
    }
3317
}
3318

    
3319
/* specific mpeg4 handling : we extract the raw parameters */
3320
static void extract_mpeg4_header(AVFormatContext *infile)
3321
{
3322
    int mpeg4_count, i, size;
3323
    AVPacket pkt;
3324
    AVStream *st;
3325
    const uint8_t *p;
3326

    
3327
    mpeg4_count = 0;
3328
    for(i=0;i<infile->nb_streams;i++) {
3329
        st = infile->streams[i];
3330
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3331
            st->codec->extradata_size == 0) {
3332
            mpeg4_count++;
3333
        }
3334
    }
3335
    if (!mpeg4_count)
3336
        return;
3337

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

    
3368
/* compute the needed AVStream for each file */
3369
static void build_file_streams(void)
3370
{
3371
    FFStream *stream, *stream_next;
3372
    AVFormatContext *infile;
3373
    int i, ret;
3374

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

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

    
3409
                for(i=0;i<infile->nb_streams;i++)
3410
                    add_av_stream1(stream, infile->streams[i]->codec);
3411

    
3412
                av_close_input_file(infile);
3413
            }
3414
        }
3415
    }
3416
}
3417

    
3418
/* compute the needed AVStream for each feed */
3419
static void build_feed_streams(void)
3420
{
3421
    FFStream *stream, *feed;
3422
    int i;
3423

    
3424
    /* gather all streams */
3425
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3426
        feed = stream->feed;
3427
        if (feed) {
3428
            if (!stream->is_feed) {
3429
                /* we handle a stream coming from a feed */
3430
                for(i=0;i<stream->nb_streams;i++)
3431
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3432
            }
3433
        }
3434
    }
3435

    
3436
    /* gather all streams */
3437
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3438
        feed = stream->feed;
3439
        if (feed) {
3440
            if (stream->is_feed) {
3441
                for(i=0;i<stream->nb_streams;i++)
3442
                    stream->feed_streams[i] = i;
3443
            }
3444
        }
3445
    }
3446

    
3447
    /* create feed files if needed */
3448
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3449
        int fd;
3450

    
3451
        if (url_exist(feed->feed_filename)) {
3452
            /* See if it matches */
3453
            AVFormatContext *s;
3454
            int matches = 0;
3455

    
3456
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3457
                /* Now see if it matches */
3458
                if (s->nb_streams == feed->nb_streams) {
3459
                    matches = 1;
3460
                    for(i=0;i<s->nb_streams;i++) {
3461
                        AVStream *sf, *ss;
3462
                        sf = feed->streams[i];
3463
                        ss = s->streams[i];
3464

    
3465
                        if (sf->index != ss->index ||
3466
                            sf->id != ss->id) {
3467
                            http_log("Index & Id do not match for stream %d (%s)\n",
3468
                                   i, feed->feed_filename);
3469
                            matches = 0;
3470
                        } else {
3471
                            AVCodecContext *ccf, *ccs;
3472

    
3473
                            ccf = sf->codec;
3474
                            ccs = ss->codec;
3475
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3476

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

    
3510
                av_close_input_file(s);
3511
            } else
3512
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3513
                        feed->feed_filename);
3514

    
3515
            if (!matches) {
3516
                if (feed->readonly) {
3517
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3518
                        feed->feed_filename);
3519
                    exit(1);
3520
                }
3521
                unlink(feed->feed_filename);
3522
            }
3523
        }
3524
        if (!url_exist(feed->feed_filename)) {
3525
            AVFormatContext s1 = {0}, *s = &s1;
3526

    
3527
            if (feed->readonly) {
3528
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3529
                    feed->feed_filename);
3530
                exit(1);
3531
            }
3532

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

    
3563
        feed->feed_write_index = ffm_read_write_index(fd);
3564
        feed->feed_size = lseek(fd, 0, SEEK_END);
3565
        /* ensure that we do not wrap before the end of file */
3566
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3567
            feed->feed_max_size = feed->feed_size;
3568

    
3569
        close(fd);
3570
    }
3571
}
3572

    
3573
/* compute the bandwidth used by each stream */
3574
static void compute_bandwidth(void)
3575
{
3576
    unsigned bandwidth;
3577
    int i;
3578
    FFStream *stream;
3579

    
3580
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3581
        bandwidth = 0;
3582
        for(i=0;i<stream->nb_streams;i++) {
3583
            AVStream *st = stream->streams[i];
3584
            switch(st->codec->codec_type) {
3585
            case CODEC_TYPE_AUDIO:
3586
            case CODEC_TYPE_VIDEO:
3587
                bandwidth += st->codec->bit_rate;
3588
                break;
3589
            default:
3590
                break;
3591
            }
3592
        }
3593
        stream->bandwidth = (bandwidth + 999) / 1000;
3594
    }
3595
}
3596

    
3597
static void get_arg(char *buf, int buf_size, const char **pp)
3598
{
3599
    const char *p;
3600
    char *q;
3601
    int quote;
3602

    
3603
    p = *pp;
3604
    while (isspace(*p)) p++;
3605
    q = buf;
3606
    quote = 0;
3607
    if (*p == '\"' || *p == '\'')
3608
        quote = *p++;
3609
    for(;;) {
3610
        if (quote) {
3611
            if (*p == quote)
3612
                break;
3613
        } else {
3614
            if (isspace(*p))
3615
                break;
3616
        }
3617
        if (*p == '\0')
3618
            break;
3619
        if ((q - buf) < buf_size - 1)
3620
            *q++ = *p;
3621
        p++;
3622
    }
3623
    *q = '\0';
3624
    if (quote && *p == quote)
3625
        p++;
3626
    *pp = p;
3627
}
3628

    
3629
/* add a codec and set the default parameters */
3630
static void add_codec(FFStream *stream, AVCodecContext *av)
3631
{
3632
    AVStream *st;
3633

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

    
3668
        if (!av->nsse_weight)
3669
            av->nsse_weight = 8;
3670

    
3671
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3672
        av->me_method = ME_EPZS;
3673
        av->rc_buffer_aggressivity = 1.0;
3674

    
3675
        if (!av->rc_eq)
3676
            av->rc_eq = "tex^qComp";
3677
        if (!av->i_quant_factor)
3678
            av->i_quant_factor = -0.8;
3679
        if (!av->b_quant_factor)
3680
            av->b_quant_factor = 1.25;
3681
        if (!av->b_quant_offset)
3682
            av->b_quant_offset = 1.25;
3683
        if (!av->rc_max_rate)
3684
            av->rc_max_rate = av->bit_rate * 2;
3685

    
3686
        if (av->rc_max_rate && !av->rc_buffer_size) {
3687
            av->rc_buffer_size = av->rc_max_rate;
3688
        }
3689

    
3690

    
3691
        break;
3692
    default:
3693
        abort();
3694
    }
3695

    
3696
    st = av_mallocz(sizeof(AVStream));
3697
    if (!st)
3698
        return;
3699
    st->codec = avcodec_alloc_context();
3700
    stream->streams[stream->nb_streams++] = st;
3701
    memcpy(st->codec, av, sizeof(AVCodecContext));
3702
}
3703

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

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

    
3711
    return p->id;
3712
}
3713

    
3714
static enum CodecID opt_video_codec(const char *arg)
3715
{
3716
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3717

    
3718
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3719
        return CODEC_ID_NONE;
3720

    
3721
    return p->id;
3722
}
3723

    
3724
/* simplistic plugin support */
3725

    
3726
#if HAVE_DLOPEN
3727
static void load_module(const char *filename)
3728
{
3729
    void *dll;
3730
    void (*init_func)(void);
3731
    dll = dlopen(filename, RTLD_NOW);
3732
    if (!dll) {
3733
        fprintf(stderr, "Could not load module '%s' - %s\n",
3734
                filename, dlerror());
3735
        return;
3736
    }
3737

    
3738
    init_func = dlsym(dll, "ffserver_module_init");
3739
    if (!init_func) {
3740
        fprintf(stderr,
3741
                "%s: init function 'ffserver_module_init()' not found\n",
3742
                filename);
3743
        dlclose(dll);
3744
    }
3745

    
3746
    init_func();
3747
}
3748
#endif
3749

    
3750
static int ffserver_opt_default(const char *opt, const char *arg,
3751
                       AVCodecContext *avctx, int type)
3752
{
3753
    int ret = 0;
3754
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3755
    if(o)
3756
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3757
    return ret;
3758
}
3759

    
3760
static int parse_ffconfig(const char *filename)
3761
{
3762
    FILE *f;
3763
    char line[1024];
3764
    char cmd[64];
3765
    char arg[1024];
3766
    const char *p;
3767
    int val, errors, line_num;
3768
    FFStream **last_stream, *stream, *redirect;
3769
    FFStream **last_feed, *feed, *s;
3770
    AVCodecContext audio_enc, video_enc;
3771
    enum CodecID audio_id, video_id;
3772

    
3773
    f = fopen(filename, "r");
3774
    if (!f) {
3775
        perror(filename);
3776
        return -1;
3777
    }
3778

    
3779
    errors = 0;
3780
    line_num = 0;
3781
    first_stream = NULL;
3782
    last_stream = &first_stream;
3783
    first_feed = NULL;
3784
    last_feed = &first_feed;
3785
    stream = NULL;
3786
    feed = NULL;
3787
    redirect = NULL;
3788
    audio_id = CODEC_ID_NONE;
3789
    video_id = CODEC_ID_NONE;
3790
    for(;;) {
3791
        if (fgets(line, sizeof(line), f) == NULL)
3792
            break;
3793
        line_num++;
3794
        p = line;
3795
        while (isspace(*p))
3796
            p++;
3797
        if (*p == '\0' || *p == '#')
3798
            continue;
3799

    
3800
        get_arg(cmd, sizeof(cmd), &p);
3801

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

    
3882
                for (s = first_feed; s; s = s->next) {
3883
                    if (!strcmp(feed->filename, s->filename)) {
3884
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3885
                                filename, line_num, s->filename);
3886
                        errors++;
3887
                    }
3888
                }
3889

    
3890
                feed->fmt = guess_format("ffm", NULL, NULL);
3891
                /* defaut feed file */
3892
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3893
                         "/tmp/%s.ffm", feed->filename);
3894
                feed->feed_max_size = 5 * 1024 * 1024;
3895
                feed->is_feed = 1;
3896
                feed->feed = feed; /* self feeding :-) */
3897

    
3898
                /* add in stream list */
3899
                *last_stream = feed;
3900
                last_stream = &feed->next;
3901
                /* add in feed list */
3902
                *last_feed = feed;
3903
                last_feed = &feed->next_feed;
3904
            }
3905
        } else if (!strcasecmp(cmd, "Launch")) {
3906
            if (feed) {
3907
                int i;
3908

    
3909
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3910

    
3911
                for (i = 0; i < 62; i++) {
3912
                    get_arg(arg, sizeof(arg), &p);
3913
                    if (!arg[0])
3914
                        break;
3915

    
3916
                    feed->child_argv[i] = av_strdup(arg);
3917
                }
3918

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

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

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

    
3983
                for (s = first_stream; s; s = s->next) {
3984
                    if (!strcmp(stream->filename, s->filename)) {
3985
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
3986
                                filename, line_num, s->filename);
3987
                        errors++;
3988
                    }
3989
                }
3990

    
3991
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3992
                /* fetch avclass so AVOption works
3993
                 * FIXME try to use avcodec_get_context_defaults2
3994
                 * without changing defaults too much */
3995
                avcodec_get_context_defaults(&video_enc);
3996
                class = video_enc.av_class;
3997
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3998
                memset(&video_enc, 0, sizeof(AVCodecContext));
3999
                audio_enc.av_class = class;
4000
                video_enc.av_class = class;
4001
                audio_id = CODEC_ID_NONE;
4002
                video_id = CODEC_ID_NONE;
4003
                if (stream->fmt) {
4004
                    audio_id = stream->fmt->audio_codec;
4005
                    video_id = stream->fmt->video_codec;
4006
                }
4007

    
4008
                *last_stream = stream;
4009
                last_stream = &stream->next;
4010
            }
4011
        } else if (!strcasecmp(cmd, "Feed")) {
4012
            get_arg(arg, sizeof(arg), &p);
4013
            if (stream) {
4014
                FFStream *sfeed;
4015

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

    
4128
                get_arg(arg, sizeof(arg), &p);
4129

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

    
4292
            get_arg(arg, sizeof(arg), &p);
4293
            if (strcasecmp(arg, "allow") == 0)
4294
                acl.action = IP_ALLOW;
4295
            else if (strcasecmp(arg, "deny") == 0)
4296
                acl.action = IP_DENY;
4297
            else {
4298
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4299
                        filename, line_num, arg);
4300
                errors++;
4301
            }
4302

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

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

    
4312
            get_arg(arg, sizeof(arg), &p);
4313

    
4314
            if (arg[0]) {
4315
                if (resolve_host(&acl.last, arg) != 0) {
4316
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4317
                            filename, line_num, arg);
4318
                    errors++;
4319
                }
4320
            }
4321

    
4322
            if (!errors) {
4323
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4324
                IPAddressACL **naclp = 0;
4325

    
4326
                acl.next = 0;
4327
                *nacl = acl;
4328

    
4329
                if (stream)
4330
                    naclp = &stream->acl;
4331
                else if (feed)
4332
                    naclp = &feed->acl;
4333
                else {
4334
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4335
                            filename, line_num);
4336
                    errors++;
4337
                }
4338

    
4339
                if (naclp) {
4340
                    while (*naclp)
4341
                        naclp = &(*naclp)->next;
4342

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

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

    
4443
    fclose(f);
4444
    if (errors)
4445
        return -1;
4446
    else
4447
        return 0;
4448
}
4449

    
4450
static void handle_child_exit(int sig)
4451
{
4452
    pid_t pid;
4453
    int status;
4454

    
4455
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4456
        FFStream *feed;
4457

    
4458
        for (feed = first_feed; feed; feed = feed->next) {
4459
            if (feed->pid == pid) {
4460
                int uptime = time(0) - feed->pid_start;
4461

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

    
4465
                if (uptime < 30)
4466
                    /* Turn off any more restarts */
4467
                    feed->child_argv = 0;
4468
            }
4469
        }
4470
    }
4471

    
4472
    need_to_start_children = 1;
4473
}
4474

    
4475
static void opt_debug(void)
4476
{
4477
    ffserver_debug = 1;
4478
    ffserver_daemon = 0;
4479
    logfilename[0] = '-';
4480
}
4481

    
4482
static void opt_show_help(void)
4483
{
4484
    printf("usage: ffserver [options]\n"
4485
           "Hyper fast multi format Audio/Video streaming server\n");
4486
    printf("\n");
4487
    show_help_options(options, "Main options:\n", 0, 0);
4488
}
4489

    
4490
static const OptionDef options[] = {
4491
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4492
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4493
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4494
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4495
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4496
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4497
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4498
    { NULL },
4499
};
4500

    
4501
int main(int argc, char **argv)
4502
{
4503
    struct sigaction sigact;
4504

    
4505
    av_register_all();
4506

    
4507
    show_banner();
4508

    
4509
    config_filename = "/etc/ffserver.conf";
4510

    
4511
    my_program_name = argv[0];
4512
    my_program_dir = getcwd(0, 0);
4513
    ffserver_daemon = 1;
4514

    
4515
    parse_options(argc, argv, options, NULL);
4516

    
4517
    unsetenv("http_proxy");             /* Kill the http_proxy */
4518

    
4519
    av_lfg_init(&random_state, ff_random_get_seed());
4520

    
4521
    memset(&sigact, 0, sizeof(sigact));
4522
    sigact.sa_handler = handle_child_exit;
4523
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4524
    sigaction(SIGCHLD, &sigact, 0);
4525

    
4526
    if (parse_ffconfig(config_filename) < 0) {
4527
        fprintf(stderr, "Incorrect config file - exiting.\n");
4528
        exit(1);
4529
    }
4530

    
4531
    /* open log file if needed */
4532
    if (logfilename[0] != '\0') {
4533
        if (!strcmp(logfilename, "-"))
4534
            logfile = stdout;
4535
        else
4536
            logfile = fopen(logfilename, "a");
4537
        av_log_set_callback(http_av_log);
4538
    }
4539

    
4540
    build_file_streams();
4541

    
4542
    build_feed_streams();
4543

    
4544
    compute_bandwidth();
4545

    
4546
    /* put the process in background and detach it from its TTY */
4547
    if (ffserver_daemon) {
4548
        int pid;
4549

    
4550
        pid = fork();
4551
        if (pid < 0) {
4552
            perror("fork");
4553
            exit(1);
4554
        } else if (pid > 0) {
4555
            /* parent : exit */
4556
            exit(0);
4557
        } else {
4558
            /* child */
4559
            setsid();
4560
            close(0);
4561
            open("/dev/null", O_RDWR);
4562
            if (strcmp(logfilename, "-") != 0) {
4563
                close(1);
4564
                dup(0);
4565
            }
4566
            close(2);
4567
            dup(0);
4568
        }
4569
    }
4570

    
4571
    /* signal init */
4572
    signal(SIGPIPE, SIG_IGN);
4573

    
4574
    if (ffserver_daemon)
4575
        chdir("/");
4576

    
4577
    if (http_server() < 0) {
4578
        http_log("Could not start server\n");
4579
        exit(1);
4580
    }
4581

    
4582
    return 0;
4583
}