Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ ffabdaa1

History | View | Annotate | Download (152 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
#include "libavformat/avformat.h"
32
#include "libavformat/network.h"
33
#include "libavformat/os_support.h"
34
#include "libavformat/rtpdec.h"
35
#include "libavformat/rtsp.h"
36
#include "libavutil/avstring.h"
37
#include "libavutil/lfg.h"
38
#include "libavutil/random_seed.h"
39
#include "libavcodec/opt.h"
40
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
44
#if HAVE_POLL_H
45
#include <poll.h>
46
#endif
47
#include <errno.h>
48
#include <sys/time.h>
49
#include <time.h>
50
#include <sys/wait.h>
51
#include <signal.h>
52
#if HAVE_DLFCN_H
53
#include <dlfcn.h>
54
#endif
55

    
56
#include "cmdutils.h"
57

    
58
const char program_name[] = "FFserver";
59
const int program_birth_year = 2000;
60

    
61
static const OptionDef options[];
62

    
63
enum HTTPState {
64
    HTTPSTATE_WAIT_REQUEST,
65
    HTTPSTATE_SEND_HEADER,
66
    HTTPSTATE_SEND_DATA_HEADER,
67
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
68
    HTTPSTATE_SEND_DATA_TRAILER,
69
    HTTPSTATE_RECEIVE_DATA,
70
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
71
    HTTPSTATE_READY,
72

    
73
    RTSPSTATE_WAIT_REQUEST,
74
    RTSPSTATE_SEND_REPLY,
75
    RTSPSTATE_SEND_PACKET,
76
};
77

    
78
static const char *http_state[] = {
79
    "HTTP_WAIT_REQUEST",
80
    "HTTP_SEND_HEADER",
81

    
82
    "SEND_DATA_HEADER",
83
    "SEND_DATA",
84
    "SEND_DATA_TRAILER",
85
    "RECEIVE_DATA",
86
    "WAIT_FEED",
87
    "READY",
88

    
89
    "RTSP_WAIT_REQUEST",
90
    "RTSP_SEND_REPLY",
91
    "RTSP_SEND_PACKET",
92
};
93

    
94
#define IOBUFFER_INIT_SIZE 8192
95

    
96
/* timeouts are in ms */
97
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
98
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
99

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

    
102
typedef struct RTSPActionServerSetup {
103
    uint32_t ipaddr;
104
    char transport_option[512];
105
} RTSPActionServerSetup;
106

    
107
typedef struct {
108
    int64_t count1, count2;
109
    int64_t time1, time2;
110
} DataRateData;
111

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

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

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

    
169
    /* RTP/UDP specific */
170
    URLContext *rtp_handles[MAX_STREAMS];
171

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

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

    
184
enum IPAddressAction {
185
    IP_ALLOW = 1,
186
    IP_DENY,
187
};
188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
311
static AVLFG random_state;
312

    
313
static FILE *logfile = NULL;
314

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

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

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

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

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

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

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

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

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

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

    
396

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

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

    
406
            feed->pid = fork();
407

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

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

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

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

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

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

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

    
449
                signal(SIGPIPE, SIG_DFL);
450

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

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

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

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

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

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

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

    
488
    return server_fd;
489
}
490

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
578
    start_children(first_feed);
579

    
580
    start_multicast();
581

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

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

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

    
654
        cur_time = av_gettime() / 1000;
655

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

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

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

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

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

    
701
static void http_send_too_busy_reply(int fd)
702
{
703
    char buffer[300];
704
    int len = snprintf(buffer, sizeof(buffer),
705
                       "HTTP/1.0 200 Server too busy\r\n"
706
                       "Content-type: text/html\r\n"
707
                       "\r\n"
708
                       "<html><head><title>Too busy</title></head><body>\r\n"
709
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
710
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
711
                       "</body></html>\r\n",
712
                       nb_connections, nb_max_connections);
713
    send(fd, buffer, len, 0);
714
}
715

    
716

    
717
static void new_connection(int server_fd, int is_rtsp)
718
{
719
    struct sockaddr_in from_addr;
720
    int fd, len;
721
    HTTPContext *c = NULL;
722

    
723
    len = sizeof(from_addr);
724
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
725
                &len);
726
    if (fd < 0) {
727
        http_log("error during accept %s\n", strerror(errno));
728
        return;
729
    }
730
    ff_socket_nonblock(fd, 1);
731

    
732
    if (nb_connections >= nb_max_connections) {
733
        http_send_too_busy_reply(fd);
734
        goto fail;
735
    }
736

    
737
    /* add a new connection */
738
    c = av_mallocz(sizeof(HTTPContext));
739
    if (!c)
740
        goto fail;
741

    
742
    c->fd = fd;
743
    c->poll_entry = NULL;
744
    c->from_addr = from_addr;
745
    c->buffer_size = IOBUFFER_INIT_SIZE;
746
    c->buffer = av_malloc(c->buffer_size);
747
    if (!c->buffer)
748
        goto fail;
749

    
750
    c->next = first_http_ctx;
751
    first_http_ctx = c;
752
    nb_connections++;
753

    
754
    start_wait_request(c, is_rtsp);
755

    
756
    return;
757

    
758
 fail:
759
    if (c) {
760
        av_free(c->buffer);
761
        av_free(c);
762
    }
763
    closesocket(fd);
764
}
765

    
766
static void close_connection(HTTPContext *c)
767
{
768
    HTTPContext **cp, *c1;
769
    int i, nb_streams;
770
    AVFormatContext *ctx;
771
    URLContext *h;
772
    AVStream *st;
773

    
774
    /* remove connection from list */
775
    cp = &first_http_ctx;
776
    while ((*cp) != NULL) {
777
        c1 = *cp;
778
        if (c1 == c)
779
            *cp = c->next;
780
        else
781
            cp = &c1->next;
782
    }
783

    
784
    /* remove references, if any (XXX: do it faster) */
785
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
786
        if (c1->rtsp_c == c)
787
            c1->rtsp_c = NULL;
788
    }
789

    
790
    /* remove connection associated resources */
791
    if (c->fd >= 0)
792
        closesocket(c->fd);
793
    if (c->fmt_in) {
794
        /* close each frame parser */
795
        for(i=0;i<c->fmt_in->nb_streams;i++) {
796
            st = c->fmt_in->streams[i];
797
            if (st->codec->codec)
798
                avcodec_close(st->codec);
799
        }
800
        av_close_input_file(c->fmt_in);
801
    }
802

    
803
    /* free RTP output streams if any */
804
    nb_streams = 0;
805
    if (c->stream)
806
        nb_streams = c->stream->nb_streams;
807

    
808
    for(i=0;i<nb_streams;i++) {
809
        ctx = c->rtp_ctx[i];
810
        if (ctx) {
811
            av_write_trailer(ctx);
812
            av_free(ctx);
813
        }
814
        h = c->rtp_handles[i];
815
        if (h)
816
            url_close(h);
817
    }
818

    
819
    ctx = &c->fmt_ctx;
820

    
821
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
822
        if (ctx->oformat) {
823
            /* prepare header */
824
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
825
                av_write_trailer(ctx);
826
                av_freep(&c->pb_buffer);
827
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
828
            }
829
        }
830
    }
831

    
832
    for(i=0; i<ctx->nb_streams; i++)
833
        av_free(ctx->streams[i]);
834

    
835
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
836
        current_bandwidth -= c->stream->bandwidth;
837

    
838
    /* signal that there is no feed if we are the feeder socket */
839
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
840
        c->stream->feed_opened = 0;
841
        close(c->feed_fd);
842
    }
843

    
844
    av_freep(&c->pb_buffer);
845
    av_freep(&c->packet_buffer);
846
    av_free(c->buffer);
847
    av_free(c);
848
    nb_connections--;
849
}
850

    
851
static int handle_connection(HTTPContext *c)
852
{
853
    int len, ret;
854

    
855
    switch(c->state) {
856
    case HTTPSTATE_WAIT_REQUEST:
857
    case RTSPSTATE_WAIT_REQUEST:
858
        /* timeout ? */
859
        if ((c->timeout - cur_time) < 0)
860
            return -1;
861
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
862
            return -1;
863

    
864
        /* no need to read if no events */
865
        if (!(c->poll_entry->revents & POLLIN))
866
            return 0;
867
        /* read the data */
868
    read_loop:
869
        len = recv(c->fd, c->buffer_ptr, 1, 0);
870
        if (len < 0) {
871
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
872
                ff_neterrno() != FF_NETERROR(EINTR))
873
                return -1;
874
        } else if (len == 0) {
875
            return -1;
876
        } else {
877
            /* search for end of request. */
878
            uint8_t *ptr;
879
            c->buffer_ptr += len;
880
            ptr = c->buffer_ptr;
881
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
882
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
883
                /* request found : parse it and reply */
884
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
885
                    ret = http_parse_request(c);
886
                } else {
887
                    ret = rtsp_parse_request(c);
888
                }
889
                if (ret < 0)
890
                    return -1;
891
            } else if (ptr >= c->buffer_end) {
892
                /* request too long: cannot do anything */
893
                return -1;
894
            } else goto read_loop;
895
        }
896
        break;
897

    
898
    case HTTPSTATE_SEND_HEADER:
899
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
900
            return -1;
901

    
902
        /* no need to write if no events */
903
        if (!(c->poll_entry->revents & POLLOUT))
904
            return 0;
905
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
906
        if (len < 0) {
907
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
908
                ff_neterrno() != FF_NETERROR(EINTR)) {
909
                /* error : close connection */
910
                av_freep(&c->pb_buffer);
911
                return -1;
912
            }
913
        } else {
914
            c->buffer_ptr += len;
915
            if (c->stream)
916
                c->stream->bytes_served += len;
917
            c->data_count += len;
918
            if (c->buffer_ptr >= c->buffer_end) {
919
                av_freep(&c->pb_buffer);
920
                /* if error, exit */
921
                if (c->http_error)
922
                    return -1;
923
                /* all the buffer was sent : synchronize to the incoming stream */
924
                c->state = HTTPSTATE_SEND_DATA_HEADER;
925
                c->buffer_ptr = c->buffer_end = c->buffer;
926
            }
927
        }
928
        break;
929

    
930
    case HTTPSTATE_SEND_DATA:
931
    case HTTPSTATE_SEND_DATA_HEADER:
932
    case HTTPSTATE_SEND_DATA_TRAILER:
933
        /* for packetized output, we consider we can always write (the
934
           input streams sets the speed). It may be better to verify
935
           that we do not rely too much on the kernel queues */
936
        if (!c->is_packetized) {
937
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
938
                return -1;
939

    
940
            /* no need to read if no events */
941
            if (!(c->poll_entry->revents & POLLOUT))
942
                return 0;
943
        }
944
        if (http_send_data(c) < 0)
945
            return -1;
946
        /* close connection if trailer sent */
947
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
948
            return -1;
949
        break;
950
    case HTTPSTATE_RECEIVE_DATA:
951
        /* no need to read if no events */
952
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
953
            return -1;
954
        if (!(c->poll_entry->revents & POLLIN))
955
            return 0;
956
        if (http_receive_data(c) < 0)
957
            return -1;
958
        break;
959
    case HTTPSTATE_WAIT_FEED:
960
        /* no need to read if no events */
961
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
962
            return -1;
963

    
964
        /* nothing to do, we'll be waken up by incoming feed packets */
965
        break;
966

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

    
1028
static int extract_rates(char *rates, int ratelen, const char *request)
1029
{
1030
    const char *p;
1031

    
1032
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1033
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1034
            const char *q = p + 7;
1035

    
1036
            while (*q && *q != '\n' && isspace(*q))
1037
                q++;
1038

    
1039
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1040
                int stream_no;
1041
                int rate_no;
1042

    
1043
                q += 20;
1044

    
1045
                memset(rates, 0xff, ratelen);
1046

    
1047
                while (1) {
1048
                    while (*q && *q != '\n' && *q != ':')
1049
                        q++;
1050

    
1051
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1052
                        break;
1053

    
1054
                    stream_no--;
1055
                    if (stream_no < ratelen && stream_no >= 0)
1056
                        rates[stream_no] = rate_no;
1057

    
1058
                    while (*q && *q != '\n' && !isspace(*q))
1059
                        q++;
1060
                }
1061

    
1062
                return 1;
1063
            }
1064
        }
1065
        p = strchr(p, '\n');
1066
        if (!p)
1067
            break;
1068

    
1069
        p++;
1070
    }
1071

    
1072
    return 0;
1073
}
1074

    
1075
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1076
{
1077
    int i;
1078
    int best_bitrate = 100000000;
1079
    int best = -1;
1080

    
1081
    for (i = 0; i < feed->nb_streams; i++) {
1082
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1083

    
1084
        if (feed_codec->codec_id != codec->codec_id ||
1085
            feed_codec->sample_rate != codec->sample_rate ||
1086
            feed_codec->width != codec->width ||
1087
            feed_codec->height != codec->height)
1088
            continue;
1089

    
1090
        /* Potential stream */
1091

    
1092
        /* We want the fastest stream less than bit_rate, or the slowest
1093
         * faster than bit_rate
1094
         */
1095

    
1096
        if (feed_codec->bit_rate <= bit_rate) {
1097
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1098
                best_bitrate = feed_codec->bit_rate;
1099
                best = i;
1100
            }
1101
        } else {
1102
            if (feed_codec->bit_rate < best_bitrate) {
1103
                best_bitrate = feed_codec->bit_rate;
1104
                best = i;
1105
            }
1106
        }
1107
    }
1108

    
1109
    return best;
1110
}
1111

    
1112
static int modify_current_stream(HTTPContext *c, char *rates)
1113
{
1114
    int i;
1115
    FFStream *req = c->stream;
1116
    int action_required = 0;
1117

    
1118
    /* Not much we can do for a feed */
1119
    if (!req->feed)
1120
        return 0;
1121

    
1122
    for (i = 0; i < req->nb_streams; i++) {
1123
        AVCodecContext *codec = req->streams[i]->codec;
1124

    
1125
        switch(rates[i]) {
1126
            case 0:
1127
                c->switch_feed_streams[i] = req->feed_streams[i];
1128
                break;
1129
            case 1:
1130
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1131
                break;
1132
            case 2:
1133
                /* Wants off or slow */
1134
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1135
#ifdef WANTS_OFF
1136
                /* This doesn't work well when it turns off the only stream! */
1137
                c->switch_feed_streams[i] = -2;
1138
                c->feed_streams[i] = -2;
1139
#endif
1140
                break;
1141
        }
1142

    
1143
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1144
            action_required = 1;
1145
    }
1146

    
1147
    return action_required;
1148
}
1149

    
1150

    
1151
static void do_switch_stream(HTTPContext *c, int i)
1152
{
1153
    if (c->switch_feed_streams[i] >= 0) {
1154
#ifdef PHILIP
1155
        c->feed_streams[i] = c->switch_feed_streams[i];
1156
#endif
1157

    
1158
        /* Now update the stream */
1159
    }
1160
    c->switch_feed_streams[i] = -1;
1161
}
1162

    
1163
/* XXX: factorize in utils.c ? */
1164
/* XXX: take care with different space meaning */
1165
static void skip_spaces(const char **pp)
1166
{
1167
    const char *p;
1168
    p = *pp;
1169
    while (*p == ' ' || *p == '\t')
1170
        p++;
1171
    *pp = p;
1172
}
1173

    
1174
static void get_word(char *buf, int buf_size, const char **pp)
1175
{
1176
    const char *p;
1177
    char *q;
1178

    
1179
    p = *pp;
1180
    skip_spaces(&p);
1181
    q = buf;
1182
    while (!isspace(*p) && *p != '\0') {
1183
        if ((q - buf) < buf_size - 1)
1184
            *q++ = *p;
1185
        p++;
1186
    }
1187
    if (buf_size > 0)
1188
        *q = '\0';
1189
    *pp = p;
1190
}
1191

    
1192
static void get_arg(char *buf, int buf_size, const char **pp)
1193
{
1194
    const char *p;
1195
    char *q;
1196
    int quote;
1197

    
1198
    p = *pp;
1199
    while (isspace(*p)) p++;
1200
    q = buf;
1201
    quote = 0;
1202
    if (*p == '\"' || *p == '\'')
1203
        quote = *p++;
1204
    for(;;) {
1205
        if (quote) {
1206
            if (*p == quote)
1207
                break;
1208
        } else {
1209
            if (isspace(*p))
1210
                break;
1211
        }
1212
        if (*p == '\0')
1213
            break;
1214
        if ((q - buf) < buf_size - 1)
1215
            *q++ = *p;
1216
        p++;
1217
    }
1218
    *q = '\0';
1219
    if (quote && *p == quote)
1220
        p++;
1221
    *pp = p;
1222
}
1223

    
1224
static int validate_acl(FFStream *stream, HTTPContext *c)
1225
{
1226
    enum IPAddressAction last_action = IP_DENY;
1227
    IPAddressACL *acl;
1228
    struct in_addr *src = &c->from_addr.sin_addr;
1229
    unsigned long src_addr = src->s_addr;
1230

    
1231
    for (acl = stream->acl; acl; acl = acl->next) {
1232
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1233
            return (acl->action == IP_ALLOW) ? 1 : 0;
1234
        last_action = acl->action;
1235
    }
1236

    
1237
    /* Nothing matched, so return not the last action */
1238
    return (last_action == IP_DENY) ? 1 : 0;
1239
}
1240

    
1241
/* compute the real filename of a file by matching it without its
1242
   extensions to all the stream filenames */
1243
static void compute_real_filename(char *filename, int max_size)
1244
{
1245
    char file1[1024];
1246
    char file2[1024];
1247
    char *p;
1248
    FFStream *stream;
1249

    
1250
    /* compute filename by matching without the file extensions */
1251
    av_strlcpy(file1, filename, sizeof(file1));
1252
    p = strrchr(file1, '.');
1253
    if (p)
1254
        *p = '\0';
1255
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1256
        av_strlcpy(file2, stream->filename, sizeof(file2));
1257
        p = strrchr(file2, '.');
1258
        if (p)
1259
            *p = '\0';
1260
        if (!strcmp(file1, file2)) {
1261
            av_strlcpy(filename, stream->filename, max_size);
1262
            break;
1263
        }
1264
    }
1265
}
1266

    
1267
enum RedirType {
1268
    REDIR_NONE,
1269
    REDIR_ASX,
1270
    REDIR_RAM,
1271
    REDIR_ASF,
1272
    REDIR_RTSP,
1273
    REDIR_SDP,
1274
};
1275

    
1276
/* parse http request and prepare header */
1277
static int http_parse_request(HTTPContext *c)
1278
{
1279
    char *p;
1280
    enum RedirType redir_type;
1281
    char cmd[32];
1282
    char info[1024], filename[1024];
1283
    char url[1024], *q;
1284
    char protocol[32];
1285
    char msg[1024];
1286
    const char *mime_type;
1287
    FFStream *stream;
1288
    int i;
1289
    char ratebuf[32];
1290
    char *useragent = 0;
1291

    
1292
    p = c->buffer;
1293
    get_word(cmd, sizeof(cmd), (const char **)&p);
1294
    av_strlcpy(c->method, cmd, sizeof(c->method));
1295

    
1296
    if (!strcmp(cmd, "GET"))
1297
        c->post = 0;
1298
    else if (!strcmp(cmd, "POST"))
1299
        c->post = 1;
1300
    else
1301
        return -1;
1302

    
1303
    get_word(url, sizeof(url), (const char **)&p);
1304
    av_strlcpy(c->url, url, sizeof(c->url));
1305

    
1306
    get_word(protocol, sizeof(protocol), (const char **)&p);
1307
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1308
        return -1;
1309

    
1310
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1311

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

    
1315
    /* find the filename and the optional info string in the request */
1316
    p = strchr(url, '?');
1317
    if (p) {
1318
        av_strlcpy(info, p, sizeof(info));
1319
        *p = '\0';
1320
    } else
1321
        info[0] = '\0';
1322

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

    
1325
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1326
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1327
            useragent = p + 11;
1328
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1329
                useragent++;
1330
            break;
1331
        }
1332
        p = strchr(p, '\n');
1333
        if (!p)
1334
            break;
1335

    
1336
        p++;
1337
    }
1338

    
1339
    redir_type = REDIR_NONE;
1340
    if (av_match_ext(filename, "asx")) {
1341
        redir_type = REDIR_ASX;
1342
        filename[strlen(filename)-1] = 'f';
1343
    } else if (av_match_ext(filename, "asf") &&
1344
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1345
        /* if this isn't WMP or lookalike, return the redirector file */
1346
        redir_type = REDIR_ASF;
1347
    } else if (av_match_ext(filename, "rpm,ram")) {
1348
        redir_type = REDIR_RAM;
1349
        strcpy(filename + strlen(filename)-2, "m");
1350
    } else if (av_match_ext(filename, "rtsp")) {
1351
        redir_type = REDIR_RTSP;
1352
        compute_real_filename(filename, sizeof(filename) - 1);
1353
    } else if (av_match_ext(filename, "sdp")) {
1354
        redir_type = REDIR_SDP;
1355
        compute_real_filename(filename, sizeof(filename) - 1);
1356
    }
1357

    
1358
    // "redirect" / request to index.html
1359
    if (!strlen(filename))
1360
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1361

    
1362
    stream = first_stream;
1363
    while (stream != NULL) {
1364
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1365
            break;
1366
        stream = stream->next;
1367
    }
1368
    if (stream == NULL) {
1369
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1370
        http_log("File '%s' not found\n", url);
1371
        goto send_error;
1372
    }
1373

    
1374
    c->stream = stream;
1375
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1376
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1377

    
1378
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1379
        c->http_error = 301;
1380
        q = c->buffer;
1381
        q += snprintf(q, c->buffer_size,
1382
                      "HTTP/1.0 301 Moved\r\n"
1383
                      "Location: %s\r\n"
1384
                      "Content-type: text/html\r\n"
1385
                      "\r\n"
1386
                      "<html><head><title>Moved</title></head><body>\r\n"
1387
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1388
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1389
        /* prepare output buffer */
1390
        c->buffer_ptr = c->buffer;
1391
        c->buffer_end = q;
1392
        c->state = HTTPSTATE_SEND_HEADER;
1393
        return 0;
1394
    }
1395

    
1396
    /* If this is WMP, get the rate information */
1397
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1398
        if (modify_current_stream(c, ratebuf)) {
1399
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1400
                if (c->switch_feed_streams[i] >= 0)
1401
                    do_switch_stream(c, i);
1402
            }
1403
        }
1404
    }
1405

    
1406
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1407
        current_bandwidth += stream->bandwidth;
1408

    
1409
    /* If already streaming this feed, do not let start another feeder. */
1410
    if (stream->feed_opened) {
1411
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1412
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1413
        goto send_error;
1414
    }
1415

    
1416
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1417
        c->http_error = 200;
1418
        q = c->buffer;
1419
        q += snprintf(q, c->buffer_size,
1420
                      "HTTP/1.0 200 Server too busy\r\n"
1421
                      "Content-type: text/html\r\n"
1422
                      "\r\n"
1423
                      "<html><head><title>Too busy</title></head><body>\r\n"
1424
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1425
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1426
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1427
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1428
        /* prepare output buffer */
1429
        c->buffer_ptr = c->buffer;
1430
        c->buffer_end = q;
1431
        c->state = HTTPSTATE_SEND_HEADER;
1432
        return 0;
1433
    }
1434

    
1435
    if (redir_type != REDIR_NONE) {
1436
        char *hostinfo = 0;
1437

    
1438
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1439
            if (strncasecmp(p, "Host:", 5) == 0) {
1440
                hostinfo = p + 5;
1441
                break;
1442
            }
1443
            p = strchr(p, '\n');
1444
            if (!p)
1445
                break;
1446

    
1447
            p++;
1448
        }
1449

    
1450
        if (hostinfo) {
1451
            char *eoh;
1452
            char hostbuf[260];
1453

    
1454
            while (isspace(*hostinfo))
1455
                hostinfo++;
1456

    
1457
            eoh = strchr(hostinfo, '\n');
1458
            if (eoh) {
1459
                if (eoh[-1] == '\r')
1460
                    eoh--;
1461

    
1462
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1463
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1464
                    hostbuf[eoh - hostinfo] = 0;
1465

    
1466
                    c->http_error = 200;
1467
                    q = c->buffer;
1468
                    switch(redir_type) {
1469
                    case REDIR_ASX:
1470
                        q += snprintf(q, c->buffer_size,
1471
                                      "HTTP/1.0 200 ASX Follows\r\n"
1472
                                      "Content-type: video/x-ms-asf\r\n"
1473
                                      "\r\n"
1474
                                      "<ASX Version=\"3\">\r\n"
1475
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1476
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1477
                                      "</ASX>\r\n", hostbuf, filename, info);
1478
                        break;
1479
                    case REDIR_RAM:
1480
                        q += snprintf(q, c->buffer_size,
1481
                                      "HTTP/1.0 200 RAM Follows\r\n"
1482
                                      "Content-type: audio/x-pn-realaudio\r\n"
1483
                                      "\r\n"
1484
                                      "# Autogenerated by ffserver\r\n"
1485
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1486
                        break;
1487
                    case REDIR_ASF:
1488
                        q += snprintf(q, c->buffer_size,
1489
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1490
                                      "Content-type: video/x-ms-asf\r\n"
1491
                                      "\r\n"
1492
                                      "[Reference]\r\n"
1493
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1494
                        break;
1495
                    case REDIR_RTSP:
1496
                        {
1497
                            char hostname[256], *p;
1498
                            /* extract only hostname */
1499
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1500
                            p = strrchr(hostname, ':');
1501
                            if (p)
1502
                                *p = '\0';
1503
                            q += snprintf(q, c->buffer_size,
1504
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1505
                                          /* XXX: incorrect mime type ? */
1506
                                          "Content-type: application/x-rtsp\r\n"
1507
                                          "\r\n"
1508
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1509
                        }
1510
                        break;
1511
                    case REDIR_SDP:
1512
                        {
1513
                            uint8_t *sdp_data;
1514
                            int sdp_data_size, len;
1515
                            struct sockaddr_in my_addr;
1516

    
1517
                            q += snprintf(q, c->buffer_size,
1518
                                          "HTTP/1.0 200 OK\r\n"
1519
                                          "Content-type: application/sdp\r\n"
1520
                                          "\r\n");
1521

    
1522
                            len = sizeof(my_addr);
1523
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1524

    
1525
                            /* XXX: should use a dynamic buffer */
1526
                            sdp_data_size = prepare_sdp_description(stream,
1527
                                                                    &sdp_data,
1528
                                                                    my_addr.sin_addr);
1529
                            if (sdp_data_size > 0) {
1530
                                memcpy(q, sdp_data, sdp_data_size);
1531
                                q += sdp_data_size;
1532
                                *q = '\0';
1533
                                av_free(sdp_data);
1534
                            }
1535
                        }
1536
                        break;
1537
                    default:
1538
                        abort();
1539
                        break;
1540
                    }
1541

    
1542
                    /* prepare output buffer */
1543
                    c->buffer_ptr = c->buffer;
1544
                    c->buffer_end = q;
1545
                    c->state = HTTPSTATE_SEND_HEADER;
1546
                    return 0;
1547
                }
1548
            }
1549
        }
1550

    
1551
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1552
        goto send_error;
1553
    }
1554

    
1555
    stream->conns_served++;
1556

    
1557
    /* XXX: add there authenticate and IP match */
1558

    
1559
    if (c->post) {
1560
        /* if post, it means a feed is being sent */
1561
        if (!stream->is_feed) {
1562
            /* However it might be a status report from WMP! Let us log the
1563
             * data as it might come in handy one day. */
1564
            char *logline = 0;
1565
            int client_id = 0;
1566

    
1567
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1568
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1569
                    logline = p;
1570
                    break;
1571
                }
1572
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1573
                    client_id = strtol(p + 18, 0, 10);
1574
                p = strchr(p, '\n');
1575
                if (!p)
1576
                    break;
1577

    
1578
                p++;
1579
            }
1580

    
1581
            if (logline) {
1582
                char *eol = strchr(logline, '\n');
1583

    
1584
                logline += 17;
1585

    
1586
                if (eol) {
1587
                    if (eol[-1] == '\r')
1588
                        eol--;
1589
                    http_log("%.*s\n", (int) (eol - logline), logline);
1590
                    c->suppress_log = 1;
1591
                }
1592
            }
1593

    
1594
#ifdef DEBUG_WMP
1595
            http_log("\nGot request:\n%s\n", c->buffer);
1596
#endif
1597

    
1598
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1599
                HTTPContext *wmpc;
1600

    
1601
                /* Now we have to find the client_id */
1602
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1603
                    if (wmpc->wmp_client_id == client_id)
1604
                        break;
1605
                }
1606

    
1607
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1608
                    wmpc->switch_pending = 1;
1609
            }
1610

    
1611
            snprintf(msg, sizeof(msg), "POST command not handled");
1612
            c->stream = 0;
1613
            goto send_error;
1614
        }
1615
        if (http_start_receive_data(c) < 0) {
1616
            snprintf(msg, sizeof(msg), "could not open feed");
1617
            goto send_error;
1618
        }
1619
        c->http_error = 0;
1620
        c->state = HTTPSTATE_RECEIVE_DATA;
1621
        return 0;
1622
    }
1623

    
1624
#ifdef DEBUG_WMP
1625
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1626
        http_log("\nGot request:\n%s\n", c->buffer);
1627
#endif
1628

    
1629
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1630
        goto send_status;
1631

    
1632
    /* open input stream */
1633
    if (open_input_stream(c, info) < 0) {
1634
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1635
        goto send_error;
1636
    }
1637

    
1638
    /* prepare http header */
1639
    q = c->buffer;
1640
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1641
    mime_type = c->stream->fmt->mime_type;
1642
    if (!mime_type)
1643
        mime_type = "application/x-octet-stream";
1644
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1645

    
1646
    /* for asf, we need extra headers */
1647
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1648
        /* Need to allocate a client id */
1649

    
1650
        c->wmp_client_id = av_lfg_get(&random_state);
1651

    
1652
        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);
1653
    }
1654
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1655
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1656

    
1657
    /* prepare output buffer */
1658
    c->http_error = 0;
1659
    c->buffer_ptr = c->buffer;
1660
    c->buffer_end = q;
1661
    c->state = HTTPSTATE_SEND_HEADER;
1662
    return 0;
1663
 send_error:
1664
    c->http_error = 404;
1665
    q = c->buffer;
1666
    q += snprintf(q, c->buffer_size,
1667
                  "HTTP/1.0 404 Not Found\r\n"
1668
                  "Content-type: text/html\r\n"
1669
                  "\r\n"
1670
                  "<html>\n"
1671
                  "<head><title>404 Not Found</title></head>\n"
1672
                  "<body>%s</body>\n"
1673
                  "</html>\n", msg);
1674
    /* prepare output buffer */
1675
    c->buffer_ptr = c->buffer;
1676
    c->buffer_end = q;
1677
    c->state = HTTPSTATE_SEND_HEADER;
1678
    return 0;
1679
 send_status:
1680
    compute_status(c);
1681
    c->http_error = 200; /* horrible : we use this value to avoid
1682
                            going to the send data state */
1683
    c->state = HTTPSTATE_SEND_HEADER;
1684
    return 0;
1685
}
1686

    
1687
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1688
{
1689
    static const char *suffix = " kMGTP";
1690
    const char *s;
1691

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

    
1694
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1695
}
1696

    
1697
static void compute_status(HTTPContext *c)
1698
{
1699
    HTTPContext *c1;
1700
    FFStream *stream;
1701
    char *p;
1702
    time_t ti;
1703
    int i, len;
1704
    ByteIOContext *pb;
1705

    
1706
    if (url_open_dyn_buf(&pb) < 0) {
1707
        /* XXX: return an error ? */
1708
        c->buffer_ptr = c->buffer;
1709
        c->buffer_end = c->buffer;
1710
        return;
1711
    }
1712

    
1713
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1714
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1715
    url_fprintf(pb, "Pragma: no-cache\r\n");
1716
    url_fprintf(pb, "\r\n");
1717

    
1718
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1719
    if (c->stream->feed_filename[0])
1720
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1721
    url_fprintf(pb, "</head>\n<body>");
1722
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1723
    /* format status */
1724
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1725
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1726
    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");
1727
    stream = first_stream;
1728
    while (stream != NULL) {
1729
        char sfilename[1024];
1730
        char *eosf;
1731

    
1732
        if (stream->feed != stream) {
1733
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1734
            eosf = sfilename + strlen(sfilename);
1735
            if (eosf - sfilename >= 4) {
1736
                if (strcmp(eosf - 4, ".asf") == 0)
1737
                    strcpy(eosf - 4, ".asx");
1738
                else if (strcmp(eosf - 3, ".rm") == 0)
1739
                    strcpy(eosf - 3, ".ram");
1740
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1741
                    /* generate a sample RTSP director if
1742
                       unicast. Generate an SDP redirector if
1743
                       multicast */
1744
                    eosf = strrchr(sfilename, '.');
1745
                    if (!eosf)
1746
                        eosf = sfilename + strlen(sfilename);
1747
                    if (stream->is_multicast)
1748
                        strcpy(eosf, ".sdp");
1749
                    else
1750
                        strcpy(eosf, ".rtsp");
1751
                }
1752
            }
1753

    
1754
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1755
                         sfilename, stream->filename);
1756
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1757
                        stream->conns_served);
1758
            fmt_bytecount(pb, stream->bytes_served);
1759
            switch(stream->stream_type) {
1760
            case STREAM_TYPE_LIVE: {
1761
                    int audio_bit_rate = 0;
1762
                    int video_bit_rate = 0;
1763
                    const char *audio_codec_name = "";
1764
                    const char *video_codec_name = "";
1765
                    const char *audio_codec_name_extra = "";
1766
                    const char *video_codec_name_extra = "";
1767

    
1768
                    for(i=0;i<stream->nb_streams;i++) {
1769
                        AVStream *st = stream->streams[i];
1770
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1771
                        switch(st->codec->codec_type) {
1772
                        case CODEC_TYPE_AUDIO:
1773
                            audio_bit_rate += st->codec->bit_rate;
1774
                            if (codec) {
1775
                                if (*audio_codec_name)
1776
                                    audio_codec_name_extra = "...";
1777
                                audio_codec_name = codec->name;
1778
                            }
1779
                            break;
1780
                        case CODEC_TYPE_VIDEO:
1781
                            video_bit_rate += st->codec->bit_rate;
1782
                            if (codec) {
1783
                                if (*video_codec_name)
1784
                                    video_codec_name_extra = "...";
1785
                                video_codec_name = codec->name;
1786
                            }
1787
                            break;
1788
                        case CODEC_TYPE_DATA:
1789
                            video_bit_rate += st->codec->bit_rate;
1790
                            break;
1791
                        default:
1792
                            abort();
1793
                        }
1794
                    }
1795
                    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",
1796
                                 stream->fmt->name,
1797
                                 stream->bandwidth,
1798
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1799
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1800
                    if (stream->feed)
1801
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1802
                    else
1803
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1804
                    url_fprintf(pb, "\n");
1805
                }
1806
                break;
1807
            default:
1808
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1809
                break;
1810
            }
1811
        }
1812
        stream = stream->next;
1813
    }
1814
    url_fprintf(pb, "</table>\n");
1815

    
1816
    stream = first_stream;
1817
    while (stream != NULL) {
1818
        if (stream->feed == stream) {
1819
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1820
            if (stream->pid) {
1821
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1822

    
1823
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1824
                {
1825
                    FILE *pid_stat;
1826
                    char ps_cmd[64];
1827

    
1828
                    /* This is somewhat linux specific I guess */
1829
                    snprintf(ps_cmd, sizeof(ps_cmd),
1830
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1831
                             stream->pid);
1832

    
1833
                    pid_stat = popen(ps_cmd, "r");
1834
                    if (pid_stat) {
1835
                        char cpuperc[10];
1836
                        char cpuused[64];
1837

    
1838
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1839
                                   cpuused) == 2) {
1840
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1841
                                         cpuperc, cpuused);
1842
                        }
1843
                        fclose(pid_stat);
1844
                    }
1845
                }
1846
#endif
1847

    
1848
                url_fprintf(pb, "<p>");
1849
            }
1850
            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");
1851

    
1852
            for (i = 0; i < stream->nb_streams; i++) {
1853
                AVStream *st = stream->streams[i];
1854
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1855
                const char *type = "unknown";
1856
                char parameters[64];
1857

    
1858
                parameters[0] = 0;
1859

    
1860
                switch(st->codec->codec_type) {
1861
                case CODEC_TYPE_AUDIO:
1862
                    type = "audio";
1863
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1864
                    break;
1865
                case CODEC_TYPE_VIDEO:
1866
                    type = "video";
1867
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1868
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1869
                    break;
1870
                default:
1871
                    abort();
1872
                }
1873
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1874
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1875
            }
1876
            url_fprintf(pb, "</table>\n");
1877

    
1878
        }
1879
        stream = stream->next;
1880
    }
1881

    
1882
    /* connection status */
1883
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1884

    
1885
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1886
                 nb_connections, nb_max_connections);
1887

    
1888
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1889
                 current_bandwidth, max_bandwidth);
1890

    
1891
    url_fprintf(pb, "<table>\n");
1892
    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");
1893
    c1 = first_http_ctx;
1894
    i = 0;
1895
    while (c1 != NULL) {
1896
        int bitrate;
1897
        int j;
1898

    
1899
        bitrate = 0;
1900
        if (c1->stream) {
1901
            for (j = 0; j < c1->stream->nb_streams; j++) {
1902
                if (!c1->stream->feed)
1903
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1904
                else if (c1->feed_streams[j] >= 0)
1905
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1906
            }
1907
        }
1908

    
1909
        i++;
1910
        p = inet_ntoa(c1->from_addr.sin_addr);
1911
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1912
                    i,
1913
                    c1->stream ? c1->stream->filename : "",
1914
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1915
                    p,
1916
                    c1->protocol,
1917
                    http_state[c1->state]);
1918
        fmt_bytecount(pb, bitrate);
1919
        url_fprintf(pb, "<td align=right>");
1920
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1921
        url_fprintf(pb, "<td align=right>");
1922
        fmt_bytecount(pb, c1->data_count);
1923
        url_fprintf(pb, "\n");
1924
        c1 = c1->next;
1925
    }
1926
    url_fprintf(pb, "</table>\n");
1927

    
1928
    /* date */
1929
    ti = time(NULL);
1930
    p = ctime(&ti);
1931
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1932
    url_fprintf(pb, "</body>\n</html>\n");
1933

    
1934
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1935
    c->buffer_ptr = c->pb_buffer;
1936
    c->buffer_end = c->pb_buffer + len;
1937
}
1938

    
1939
/* check if the parser needs to be opened for stream i */
1940
static void open_parser(AVFormatContext *s, int i)
1941
{
1942
    AVStream *st = s->streams[i];
1943
    AVCodec *codec;
1944

    
1945
    if (!st->codec->codec) {
1946
        codec = avcodec_find_decoder(st->codec->codec_id);
1947
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1948
            st->codec->parse_only = 1;
1949
            if (avcodec_open(st->codec, codec) < 0)
1950
                st->codec->parse_only = 0;
1951
        }
1952
    }
1953
}
1954

    
1955
static int open_input_stream(HTTPContext *c, const char *info)
1956
{
1957
    char buf[128];
1958
    char input_filename[1024];
1959
    AVFormatContext *s;
1960
    int buf_size, i, ret;
1961
    int64_t stream_pos;
1962

    
1963
    /* find file name */
1964
    if (c->stream->feed) {
1965
        strcpy(input_filename, c->stream->feed->feed_filename);
1966
        buf_size = FFM_PACKET_SIZE;
1967
        /* compute position (absolute time) */
1968
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1969
            stream_pos = parse_date(buf, 0);
1970
            if (stream_pos == INT64_MIN)
1971
                return -1;
1972
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1973
            int prebuffer = strtol(buf, 0, 10);
1974
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1975
        } else
1976
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1977
    } else {
1978
        strcpy(input_filename, c->stream->feed_filename);
1979
        buf_size = 0;
1980
        /* compute position (relative time) */
1981
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1982
            stream_pos = parse_date(buf, 1);
1983
            if (stream_pos == INT64_MIN)
1984
                return -1;
1985
        } else
1986
            stream_pos = 0;
1987
    }
1988
    if (input_filename[0] == '\0')
1989
        return -1;
1990

    
1991
    /* open stream */
1992
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1993
                                  buf_size, c->stream->ap_in)) < 0) {
1994
        http_log("could not open %s: %d\n", input_filename, ret);
1995
        return -1;
1996
    }
1997
    s->flags |= AVFMT_FLAG_GENPTS;
1998
    c->fmt_in = s;
1999
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2000
        http_log("Could not find stream info '%s'\n", input_filename);
2001
        av_close_input_file(s);
2002
        return -1;
2003
    }
2004

    
2005
    /* open each parser */
2006
    for(i=0;i<s->nb_streams;i++)
2007
        open_parser(s, i);
2008

    
2009
    /* choose stream as clock source (we favorize video stream if
2010
       present) for packet sending */
2011
    c->pts_stream_index = 0;
2012
    for(i=0;i<c->stream->nb_streams;i++) {
2013
        if (c->pts_stream_index == 0 &&
2014
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2015
            c->pts_stream_index = i;
2016
        }
2017
    }
2018

    
2019
#if 1
2020
    if (c->fmt_in->iformat->read_seek)
2021
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2022
#endif
2023
    /* set the start time (needed for maxtime and RTP packet timing) */
2024
    c->start_time = cur_time;
2025
    c->first_pts = AV_NOPTS_VALUE;
2026
    return 0;
2027
}
2028

    
2029
/* return the server clock (in us) */
2030
static int64_t get_server_clock(HTTPContext *c)
2031
{
2032
    /* compute current pts value from system time */
2033
    return (cur_time - c->start_time) * 1000;
2034
}
2035

    
2036
/* return the estimated time at which the current packet must be sent
2037
   (in us) */
2038
static int64_t get_packet_send_clock(HTTPContext *c)
2039
{
2040
    int bytes_left, bytes_sent, frame_bytes;
2041

    
2042
    frame_bytes = c->cur_frame_bytes;
2043
    if (frame_bytes <= 0)
2044
        return c->cur_pts;
2045
    else {
2046
        bytes_left = c->buffer_end - c->buffer_ptr;
2047
        bytes_sent = frame_bytes - bytes_left;
2048
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2049
    }
2050
}
2051

    
2052

    
2053
static int http_prepare_data(HTTPContext *c)
2054
{
2055
    int i, len, ret;
2056
    AVFormatContext *ctx;
2057

    
2058
    av_freep(&c->pb_buffer);
2059
    switch(c->state) {
2060
    case HTTPSTATE_SEND_DATA_HEADER:
2061
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2062
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2063
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2064
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2065
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2066

    
2067
        for(i=0;i<c->stream->nb_streams;i++) {
2068
            AVStream *st;
2069
            AVStream *src;
2070
            st = av_mallocz(sizeof(AVStream));
2071
            c->fmt_ctx.streams[i] = st;
2072
            /* if file or feed, then just take streams from FFStream struct */
2073
            if (!c->stream->feed ||
2074
                c->stream->feed == c->stream)
2075
                src = c->stream->streams[i];
2076
            else
2077
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2078

    
2079
            *st = *src;
2080
            st->priv_data = 0;
2081
            st->codec->frame_number = 0; /* XXX: should be done in
2082
                                           AVStream, not in codec */
2083
        }
2084
        /* set output format parameters */
2085
        c->fmt_ctx.oformat = c->stream->fmt;
2086
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2087

    
2088
        c->got_key_frame = 0;
2089

    
2090
        /* prepare header and save header data in a stream */
2091
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2092
            /* XXX: potential leak */
2093
            return -1;
2094
        }
2095
        c->fmt_ctx.pb->is_streamed = 1;
2096

    
2097
        /*
2098
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2099
         * Default value from FFmpeg
2100
         * Try to set it use configuration option
2101
         */
2102
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2103
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2104

    
2105
        av_set_parameters(&c->fmt_ctx, NULL);
2106
        if (av_write_header(&c->fmt_ctx) < 0) {
2107
            http_log("Error writing output header\n");
2108
            return -1;
2109
        }
2110

    
2111
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2112
        c->buffer_ptr = c->pb_buffer;
2113
        c->buffer_end = c->pb_buffer + len;
2114

    
2115
        c->state = HTTPSTATE_SEND_DATA;
2116
        c->last_packet_sent = 0;
2117
        break;
2118
    case HTTPSTATE_SEND_DATA:
2119
        /* find a new packet */
2120
        /* read a packet from the input stream */
2121
        if (c->stream->feed)
2122
            ffm_set_write_index(c->fmt_in,
2123
                                c->stream->feed->feed_write_index,
2124
                                c->stream->feed->feed_size);
2125

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

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

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

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

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

    
2273
        c->last_packet_sent = 1;
2274
        break;
2275
    }
2276
    return 0;
2277
}
2278

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

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

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

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

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

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

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

    
2401
static int http_start_receive_data(HTTPContext *c)
2402
{
2403
    int fd;
2404

    
2405
    if (c->stream->feed_opened)
2406
        return -1;
2407

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

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

    
2420
    if (c->stream->truncate) {
2421
        /* truncate feed file */
2422
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2423
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2424
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2425
    } else {
2426
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2427
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2428
            return -1;
2429
        }
2430
    }
2431

    
2432
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2433
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2434
    lseek(fd, 0, SEEK_SET);
2435

    
2436
    /* init buffer input */
2437
    c->buffer_ptr = c->buffer;
2438
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2439
    c->stream->feed_opened = 1;
2440
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2441
    return 0;
2442
}
2443

    
2444
static int http_receive_data(HTTPContext *c)
2445
{
2446
    HTTPContext *c1;
2447
    int len, loop_run = 0;
2448

    
2449
    while (c->chunked_encoding && !c->chunk_size &&
2450
           c->buffer_end > c->buffer_ptr) {
2451
        /* read chunk header, if present */
2452
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2453

    
2454
        if (len < 0) {
2455
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2456
                ff_neterrno() != FF_NETERROR(EINTR))
2457
                /* error : close connection */
2458
                goto fail;
2459
        } else if (len == 0) {
2460
            /* end of connection : close it */
2461
            goto fail;
2462
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2463
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2464
            c->chunk_size = strtol(c->buffer, 0, 16);
2465
            if (c->chunk_size == 0) // end of stream
2466
                goto fail;
2467
            c->buffer_ptr = c->buffer;
2468
            break;
2469
        } else if (++loop_run > 10) {
2470
            /* no chunk header, abort */
2471
            goto fail;
2472
        } else {
2473
            c->buffer_ptr++;
2474
        }
2475
    }
2476

    
2477
    if (c->buffer_end > c->buffer_ptr) {
2478
        len = recv(c->fd, c->buffer_ptr,
2479
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2480
        if (len < 0) {
2481
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2482
                ff_neterrno() != FF_NETERROR(EINTR))
2483
                /* error : close connection */
2484
                goto fail;
2485
        } else if (len == 0)
2486
            /* end of connection : close it */
2487
            goto fail;
2488
        else {
2489
            c->chunk_size -= len;
2490
            c->buffer_ptr += len;
2491
            c->data_count += len;
2492
            update_datarate(&c->datarate, c->data_count);
2493
        }
2494
    }
2495

    
2496
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2497
        if (c->buffer[0] != 'f' ||
2498
            c->buffer[1] != 'm') {
2499
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2500
            goto fail;
2501
        }
2502
    }
2503

    
2504
    if (c->buffer_ptr >= c->buffer_end) {
2505
        FFStream *feed = c->stream;
2506
        /* a packet has been received : write it in the store, except
2507
           if header */
2508
        if (c->data_count > FFM_PACKET_SIZE) {
2509

    
2510
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2511
            /* XXX: use llseek or url_seek */
2512
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2513
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2514
                http_log("Error writing to feed file: %s\n", strerror(errno));
2515
                goto fail;
2516
            }
2517

    
2518
            feed->feed_write_index += FFM_PACKET_SIZE;
2519
            /* update file size */
2520
            if (feed->feed_write_index > c->stream->feed_size)
2521
                feed->feed_size = feed->feed_write_index;
2522

    
2523
            /* handle wrap around if max file size reached */
2524
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2525
                feed->feed_write_index = FFM_PACKET_SIZE;
2526

    
2527
            /* write index */
2528
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2529
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2530
                goto fail;
2531
            }
2532

    
2533
            /* wake up any waiting connections */
2534
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2535
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2536
                    c1->stream->feed == c->stream->feed)
2537
                    c1->state = HTTPSTATE_SEND_DATA;
2538
            }
2539
        } else {
2540
            /* We have a header in our hands that contains useful data */
2541
            AVFormatContext *s = NULL;
2542
            ByteIOContext *pb;
2543
            AVInputFormat *fmt_in;
2544
            int i;
2545

    
2546
            /* use feed output format name to find corresponding input format */
2547
            fmt_in = av_find_input_format(feed->fmt->name);
2548
            if (!fmt_in)
2549
                goto fail;
2550

    
2551
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2552
            pb->is_streamed = 1;
2553

    
2554
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2555
                av_free(pb);
2556
                goto fail;
2557
            }
2558

    
2559
            /* Now we have the actual streams */
2560
            if (s->nb_streams != feed->nb_streams) {
2561
                av_close_input_stream(s);
2562
                av_free(pb);
2563
                http_log("Feed '%s' stream number does not match registered feed\n",
2564
                         c->stream->feed_filename);
2565
                goto fail;
2566
            }
2567

    
2568
            for (i = 0; i < s->nb_streams; i++) {
2569
                AVStream *fst = feed->streams[i];
2570
                AVStream *st = s->streams[i];
2571
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2572
                if (fst->codec->extradata_size) {
2573
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2574
                    if (!fst->codec->extradata)
2575
                        goto fail;
2576
                    memcpy(fst->codec->extradata, st->codec->extradata,
2577
                           fst->codec->extradata_size);
2578
                }
2579
            }
2580

    
2581
            av_close_input_stream(s);
2582
            av_free(pb);
2583
        }
2584
        c->buffer_ptr = c->buffer;
2585
    }
2586

    
2587
    return 0;
2588
 fail:
2589
    c->stream->feed_opened = 0;
2590
    close(c->feed_fd);
2591
    /* wake up any waiting connections to stop waiting for feed */
2592
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2593
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2594
            c1->stream->feed == c->stream->feed)
2595
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2596
    }
2597
    return -1;
2598
}
2599

    
2600
/********************************************************************/
2601
/* RTSP handling */
2602

    
2603
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2604
{
2605
    const char *str;
2606
    time_t ti;
2607
    char *p;
2608
    char buf2[32];
2609

    
2610
    switch(error_number) {
2611
    case RTSP_STATUS_OK:
2612
        str = "OK";
2613
        break;
2614
    case RTSP_STATUS_METHOD:
2615
        str = "Method Not Allowed";
2616
        break;
2617
    case RTSP_STATUS_BANDWIDTH:
2618
        str = "Not Enough Bandwidth";
2619
        break;
2620
    case RTSP_STATUS_SESSION:
2621
        str = "Session Not Found";
2622
        break;
2623
    case RTSP_STATUS_STATE:
2624
        str = "Method Not Valid in This State";
2625
        break;
2626
    case RTSP_STATUS_AGGREGATE:
2627
        str = "Aggregate operation not allowed";
2628
        break;
2629
    case RTSP_STATUS_ONLY_AGGREGATE:
2630
        str = "Only aggregate operation allowed";
2631
        break;
2632
    case RTSP_STATUS_TRANSPORT:
2633
        str = "Unsupported transport";
2634
        break;
2635
    case RTSP_STATUS_INTERNAL:
2636
        str = "Internal Server Error";
2637
        break;
2638
    case RTSP_STATUS_SERVICE:
2639
        str = "Service Unavailable";
2640
        break;
2641
    case RTSP_STATUS_VERSION:
2642
        str = "RTSP Version not supported";
2643
        break;
2644
    default:
2645
        str = "Unknown Error";
2646
        break;
2647
    }
2648

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

    
2652
    /* output GMT time */
2653
    ti = time(NULL);
2654
    p = ctime(&ti);
2655
    strcpy(buf2, p);
2656
    p = buf2 + strlen(p) - 1;
2657
    if (*p == '\n')
2658
        *p = '\0';
2659
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2660
}
2661

    
2662
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2663
{
2664
    rtsp_reply_header(c, error_number);
2665
    url_fprintf(c->pb, "\r\n");
2666
}
2667

    
2668
static int rtsp_parse_request(HTTPContext *c)
2669
{
2670
    const char *p, *p1, *p2;
2671
    char cmd[32];
2672
    char url[1024];
2673
    char protocol[32];
2674
    char line[1024];
2675
    int len;
2676
    RTSPMessageHeader header1, *header = &header1;
2677

    
2678
    c->buffer_ptr[0] = '\0';
2679
    p = c->buffer;
2680

    
2681
    get_word(cmd, sizeof(cmd), &p);
2682
    get_word(url, sizeof(url), &p);
2683
    get_word(protocol, sizeof(protocol), &p);
2684

    
2685
    av_strlcpy(c->method, cmd, sizeof(c->method));
2686
    av_strlcpy(c->url, url, sizeof(c->url));
2687
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2688

    
2689
    if (url_open_dyn_buf(&c->pb) < 0) {
2690
        /* XXX: cannot do more */
2691
        c->pb = NULL; /* safety */
2692
        return -1;
2693
    }
2694

    
2695
    /* check version name */
2696
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2697
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2698
        goto the_end;
2699
    }
2700

    
2701
    /* parse each header line */
2702
    memset(header, 0, sizeof(*header));
2703
    /* skip to next line */
2704
    while (*p != '\n' && *p != '\0')
2705
        p++;
2706
    if (*p == '\n')
2707
        p++;
2708
    while (*p != '\0') {
2709
        p1 = strchr(p, '\n');
2710
        if (!p1)
2711
            break;
2712
        p2 = p1;
2713
        if (p2 > p && p2[-1] == '\r')
2714
            p2--;
2715
        /* skip empty line */
2716
        if (p2 == p)
2717
            break;
2718
        len = p2 - p;
2719
        if (len > sizeof(line) - 1)
2720
            len = sizeof(line) - 1;
2721
        memcpy(line, p, len);
2722
        line[len] = '\0';
2723
        ff_rtsp_parse_line(header, line);
2724
        p = p1 + 1;
2725
    }
2726

    
2727
    /* handle sequence number */
2728
    c->seq = header->seq;
2729

    
2730
    if (!strcmp(cmd, "DESCRIBE"))
2731
        rtsp_cmd_describe(c, url);
2732
    else if (!strcmp(cmd, "OPTIONS"))
2733
        rtsp_cmd_options(c, url);
2734
    else if (!strcmp(cmd, "SETUP"))
2735
        rtsp_cmd_setup(c, url, header);
2736
    else if (!strcmp(cmd, "PLAY"))
2737
        rtsp_cmd_play(c, url, header);
2738
    else if (!strcmp(cmd, "PAUSE"))
2739
        rtsp_cmd_pause(c, url, header);
2740
    else if (!strcmp(cmd, "TEARDOWN"))
2741
        rtsp_cmd_teardown(c, url, header);
2742
    else
2743
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2744

    
2745
 the_end:
2746
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2747
    c->pb = NULL; /* safety */
2748
    if (len < 0) {
2749
        /* XXX: cannot do more */
2750
        return -1;
2751
    }
2752
    c->buffer_ptr = c->pb_buffer;
2753
    c->buffer_end = c->pb_buffer + len;
2754
    c->state = RTSPSTATE_SEND_REPLY;
2755
    return 0;
2756
}
2757

    
2758
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2759
                                   struct in_addr my_ip)
2760
{
2761
    AVFormatContext *avc;
2762
    AVStream avs[MAX_STREAMS];
2763
    int i;
2764

    
2765
    avc =  avformat_alloc_context();
2766
    if (avc == NULL) {
2767
        return -1;
2768
    }
2769
    av_metadata_set(&avc->metadata, "title",
2770
                    stream->title[0] ? stream->title : "No Title");
2771
    avc->nb_streams = stream->nb_streams;
2772
    if (stream->is_multicast) {
2773
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2774
                 inet_ntoa(stream->multicast_ip),
2775
                 stream->multicast_port, stream->multicast_ttl);
2776
    }
2777

    
2778
    for(i = 0; i < stream->nb_streams; i++) {
2779
        avc->streams[i] = &avs[i];
2780
        avc->streams[i]->codec = stream->streams[i]->codec;
2781
    }
2782
    *pbuffer = av_mallocz(2048);
2783
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2784
    av_free(avc);
2785

    
2786
    return strlen(*pbuffer);
2787
}
2788

    
2789
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2790
{
2791
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2792
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2793
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2794
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2795
    url_fprintf(c->pb, "\r\n");
2796
}
2797

    
2798
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2799
{
2800
    FFStream *stream;
2801
    char path1[1024];
2802
    const char *path;
2803
    uint8_t *content;
2804
    int content_length, len;
2805
    struct sockaddr_in my_addr;
2806

    
2807
    /* find which url is asked */
2808
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2809
    path = path1;
2810
    if (*path == '/')
2811
        path++;
2812

    
2813
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2814
        if (!stream->is_feed &&
2815
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2816
            !strcmp(path, stream->filename)) {
2817
            goto found;
2818
        }
2819
    }
2820
    /* no stream found */
2821
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2822
    return;
2823

    
2824
 found:
2825
    /* prepare the media description in sdp format */
2826

    
2827
    /* get the host IP */
2828
    len = sizeof(my_addr);
2829
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2830
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2831
    if (content_length < 0) {
2832
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2833
        return;
2834
    }
2835
    rtsp_reply_header(c, RTSP_STATUS_OK);
2836
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2837
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2838
    url_fprintf(c->pb, "\r\n");
2839
    put_buffer(c->pb, content, content_length);
2840
}
2841

    
2842
static HTTPContext *find_rtp_session(const char *session_id)
2843
{
2844
    HTTPContext *c;
2845

    
2846
    if (session_id[0] == '\0')
2847
        return NULL;
2848

    
2849
    for(c = first_http_ctx; c != NULL; c = c->next) {
2850
        if (!strcmp(c->session_id, session_id))
2851
            return c;
2852
    }
2853
    return NULL;
2854
}
2855

    
2856
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2857
{
2858
    RTSPTransportField *th;
2859
    int i;
2860

    
2861
    for(i=0;i<h->nb_transports;i++) {
2862
        th = &h->transports[i];
2863
        if (th->lower_transport == lower_transport)
2864
            return th;
2865
    }
2866
    return NULL;
2867
}
2868

    
2869
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2870
                           RTSPMessageHeader *h)
2871
{
2872
    FFStream *stream;
2873
    int stream_index, port;
2874
    char buf[1024];
2875
    char path1[1024];
2876
    const char *path;
2877
    HTTPContext *rtp_c;
2878
    RTSPTransportField *th;
2879
    struct sockaddr_in dest_addr;
2880
    RTSPActionServerSetup setup;
2881

    
2882
    /* find which url is asked */
2883
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2884
    path = path1;
2885
    if (*path == '/')
2886
        path++;
2887

    
2888
    /* now check each stream */
2889
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2890
        if (!stream->is_feed &&
2891
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2892
            /* accept aggregate filenames only if single stream */
2893
            if (!strcmp(path, stream->filename)) {
2894
                if (stream->nb_streams != 1) {
2895
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2896
                    return;
2897
                }
2898
                stream_index = 0;
2899
                goto found;
2900
            }
2901

    
2902
            for(stream_index = 0; stream_index < stream->nb_streams;
2903
                stream_index++) {
2904
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2905
                         stream->filename, stream_index);
2906
                if (!strcmp(path, buf))
2907
                    goto found;
2908
            }
2909
        }
2910
    }
2911
    /* no stream found */
2912
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2913
    return;
2914
 found:
2915

    
2916
    /* generate session id if needed */
2917
    if (h->session_id[0] == '\0')
2918
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2919
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2920

    
2921
    /* find rtp session, and create it if none found */
2922
    rtp_c = find_rtp_session(h->session_id);
2923
    if (!rtp_c) {
2924
        /* always prefer UDP */
2925
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2926
        if (!th) {
2927
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2928
            if (!th) {
2929
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2930
                return;
2931
            }
2932
        }
2933

    
2934
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2935
                                   th->lower_transport);
2936
        if (!rtp_c) {
2937
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2938
            return;
2939
        }
2940

    
2941
        /* open input stream */
2942
        if (open_input_stream(rtp_c, "") < 0) {
2943
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2944
            return;
2945
        }
2946
    }
2947

    
2948
    /* test if stream is OK (test needed because several SETUP needs
2949
       to be done for a given file) */
2950
    if (rtp_c->stream != stream) {
2951
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2952
        return;
2953
    }
2954

    
2955
    /* test if stream is already set up */
2956
    if (rtp_c->rtp_ctx[stream_index]) {
2957
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2958
        return;
2959
    }
2960

    
2961
    /* check transport */
2962
    th = find_transport(h, rtp_c->rtp_protocol);
2963
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2964
                th->client_port_min <= 0)) {
2965
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2966
        return;
2967
    }
2968

    
2969
    /* setup default options */
2970
    setup.transport_option[0] = '\0';
2971
    dest_addr = rtp_c->from_addr;
2972
    dest_addr.sin_port = htons(th->client_port_min);
2973

    
2974
    /* setup stream */
2975
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2976
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2977
        return;
2978
    }
2979

    
2980
    /* now everything is OK, so we can send the connection parameters */
2981
    rtsp_reply_header(c, RTSP_STATUS_OK);
2982
    /* session ID */
2983
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2984

    
2985
    switch(rtp_c->rtp_protocol) {
2986
    case RTSP_LOWER_TRANSPORT_UDP:
2987
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2988
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2989
                    "client_port=%d-%d;server_port=%d-%d",
2990
                    th->client_port_min, th->client_port_min + 1,
2991
                    port, port + 1);
2992
        break;
2993
    case RTSP_LOWER_TRANSPORT_TCP:
2994
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2995
                    stream_index * 2, stream_index * 2 + 1);
2996
        break;
2997
    default:
2998
        break;
2999
    }
3000
    if (setup.transport_option[0] != '\0')
3001
        url_fprintf(c->pb, ";%s", setup.transport_option);
3002
    url_fprintf(c->pb, "\r\n");
3003

    
3004

    
3005
    url_fprintf(c->pb, "\r\n");
3006
}
3007

    
3008

    
3009
/* find an rtp connection by using the session ID. Check consistency
3010
   with filename */
3011
static HTTPContext *find_rtp_session_with_url(const char *url,
3012
                                              const char *session_id)
3013
{
3014
    HTTPContext *rtp_c;
3015
    char path1[1024];
3016
    const char *path;
3017
    char buf[1024];
3018
    int s;
3019

    
3020
    rtp_c = find_rtp_session(session_id);
3021
    if (!rtp_c)
3022
        return NULL;
3023

    
3024
    /* find which url is asked */
3025
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3026
    path = path1;
3027
    if (*path == '/')
3028
        path++;
3029
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3030
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3031
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3032
        rtp_c->stream->filename, s);
3033
      if(!strncmp(path, buf, sizeof(buf))) {
3034
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3035
        return rtp_c;
3036
      }
3037
    }
3038
    return NULL;
3039
}
3040

    
3041
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3042
{
3043
    HTTPContext *rtp_c;
3044

    
3045
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3046
    if (!rtp_c) {
3047
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3048
        return;
3049
    }
3050

    
3051
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3052
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3053
        rtp_c->state != HTTPSTATE_READY) {
3054
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3055
        return;
3056
    }
3057

    
3058
    rtp_c->state = HTTPSTATE_SEND_DATA;
3059

    
3060
    /* now everything is OK, so we can send the connection parameters */
3061
    rtsp_reply_header(c, RTSP_STATUS_OK);
3062
    /* session ID */
3063
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3064
    url_fprintf(c->pb, "\r\n");
3065
}
3066

    
3067
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3068
{
3069
    HTTPContext *rtp_c;
3070

    
3071
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3072
    if (!rtp_c) {
3073
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3074
        return;
3075
    }
3076

    
3077
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3078
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3079
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3080
        return;
3081
    }
3082

    
3083
    rtp_c->state = HTTPSTATE_READY;
3084
    rtp_c->first_pts = AV_NOPTS_VALUE;
3085
    /* now everything is OK, so we can send the connection parameters */
3086
    rtsp_reply_header(c, RTSP_STATUS_OK);
3087
    /* session ID */
3088
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3089
    url_fprintf(c->pb, "\r\n");
3090
}
3091

    
3092
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3093
{
3094
    HTTPContext *rtp_c;
3095
    char session_id[32];
3096

    
3097
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3098
    if (!rtp_c) {
3099
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3100
        return;
3101
    }
3102

    
3103
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3104

    
3105
    /* abort the session */
3106
    close_connection(rtp_c);
3107

    
3108
    /* now everything is OK, so we can send the connection parameters */
3109
    rtsp_reply_header(c, RTSP_STATUS_OK);
3110
    /* session ID */
3111
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3112
    url_fprintf(c->pb, "\r\n");
3113
}
3114

    
3115

    
3116
/********************************************************************/
3117
/* RTP handling */
3118

    
3119
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3120
                                       FFStream *stream, const char *session_id,
3121
                                       enum RTSPLowerTransport rtp_protocol)
3122
{
3123
    HTTPContext *c = NULL;
3124
    const char *proto_str;
3125

    
3126
    /* XXX: should output a warning page when coming
3127
       close to the connection limit */
3128
    if (nb_connections >= nb_max_connections)
3129
        goto fail;
3130

    
3131
    /* add a new connection */
3132
    c = av_mallocz(sizeof(HTTPContext));
3133
    if (!c)
3134
        goto fail;
3135

    
3136
    c->fd = -1;
3137
    c->poll_entry = NULL;
3138
    c->from_addr = *from_addr;
3139
    c->buffer_size = IOBUFFER_INIT_SIZE;
3140
    c->buffer = av_malloc(c->buffer_size);
3141
    if (!c->buffer)
3142
        goto fail;
3143
    nb_connections++;
3144
    c->stream = stream;
3145
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3146
    c->state = HTTPSTATE_READY;
3147
    c->is_packetized = 1;
3148
    c->rtp_protocol = rtp_protocol;
3149

    
3150
    /* protocol is shown in statistics */
3151
    switch(c->rtp_protocol) {
3152
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3153
        proto_str = "MCAST";
3154
        break;
3155
    case RTSP_LOWER_TRANSPORT_UDP:
3156
        proto_str = "UDP";
3157
        break;
3158
    case RTSP_LOWER_TRANSPORT_TCP:
3159
        proto_str = "TCP";
3160
        break;
3161
    default:
3162
        proto_str = "???";
3163
        break;
3164
    }
3165
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3166
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3167

    
3168
    current_bandwidth += stream->bandwidth;
3169

    
3170
    c->next = first_http_ctx;
3171
    first_http_ctx = c;
3172
    return c;
3173

    
3174
 fail:
3175
    if (c) {
3176
        av_free(c->buffer);
3177
        av_free(c);
3178
    }
3179
    return NULL;
3180
}
3181

    
3182
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3183
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3184
   used. */
3185
static int rtp_new_av_stream(HTTPContext *c,
3186
                             int stream_index, struct sockaddr_in *dest_addr,
3187
                             HTTPContext *rtsp_c)
3188
{
3189
    AVFormatContext *ctx;
3190
    AVStream *st;
3191
    char *ipaddr;
3192
    URLContext *h = NULL;
3193
    uint8_t *dummy_buf;
3194
    int max_packet_size;
3195

    
3196
    /* now we can open the relevant output stream */
3197
    ctx = avformat_alloc_context();
3198
    if (!ctx)
3199
        return -1;
3200
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3201

    
3202
    st = av_mallocz(sizeof(AVStream));
3203
    if (!st)
3204
        goto fail;
3205
    st->codec= avcodec_alloc_context();
3206
    ctx->nb_streams = 1;
3207
    ctx->streams[0] = st;
3208

    
3209
    if (!c->stream->feed ||
3210
        c->stream->feed == c->stream)
3211
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3212
    else
3213
        memcpy(st,
3214
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3215
               sizeof(AVStream));
3216
    st->priv_data = NULL;
3217

    
3218
    /* build destination RTP address */
3219
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3220

    
3221
    switch(c->rtp_protocol) {
3222
    case RTSP_LOWER_TRANSPORT_UDP:
3223
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3224
        /* RTP/UDP case */
3225

    
3226
        /* XXX: also pass as parameter to function ? */
3227
        if (c->stream->is_multicast) {
3228
            int ttl;
3229
            ttl = c->stream->multicast_ttl;
3230
            if (!ttl)
3231
                ttl = 16;
3232
            snprintf(ctx->filename, sizeof(ctx->filename),
3233
                     "rtp://%s:%d?multicast=1&ttl=%d",
3234
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3235
        } else {
3236
            snprintf(ctx->filename, sizeof(ctx->filename),
3237
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3238
        }
3239

    
3240
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3241
            goto fail;
3242
        c->rtp_handles[stream_index] = h;
3243
        max_packet_size = url_get_max_packet_size(h);
3244
        break;
3245
    case RTSP_LOWER_TRANSPORT_TCP:
3246
        /* RTP/TCP case */
3247
        c->rtsp_c = rtsp_c;
3248
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3249
        break;
3250
    default:
3251
        goto fail;
3252
    }
3253

    
3254
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3255
             ipaddr, ntohs(dest_addr->sin_port),
3256
             c->stream->filename, stream_index, c->protocol);
3257

    
3258
    /* normally, no packets should be output here, but the packet size may be checked */
3259
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3260
        /* XXX: close stream */
3261
        goto fail;
3262
    }
3263
    av_set_parameters(ctx, NULL);
3264
    if (av_write_header(ctx) < 0) {
3265
    fail:
3266
        if (h)
3267
            url_close(h);
3268
        av_free(ctx);
3269
        return -1;
3270
    }
3271
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3272
    av_free(dummy_buf);
3273

    
3274
    c->rtp_ctx[stream_index] = ctx;
3275
    return 0;
3276
}
3277

    
3278
/********************************************************************/
3279
/* ffserver initialization */
3280

    
3281
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3282
{
3283
    AVStream *fst;
3284

    
3285
    fst = av_mallocz(sizeof(AVStream));
3286
    if (!fst)
3287
        return NULL;
3288
    fst->codec= avcodec_alloc_context();
3289
    fst->priv_data = av_mallocz(sizeof(FeedData));
3290
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3291
    fst->index = stream->nb_streams;
3292
    av_set_pts_info(fst, 33, 1, 90000);
3293
    stream->streams[stream->nb_streams++] = fst;
3294
    return fst;
3295
}
3296

    
3297
/* return the stream number in the feed */
3298
static int add_av_stream(FFStream *feed, AVStream *st)
3299
{
3300
    AVStream *fst;
3301
    AVCodecContext *av, *av1;
3302
    int i;
3303

    
3304
    av = st->codec;
3305
    for(i=0;i<feed->nb_streams;i++) {
3306
        st = feed->streams[i];
3307
        av1 = st->codec;
3308
        if (av1->codec_id == av->codec_id &&
3309
            av1->codec_type == av->codec_type &&
3310
            av1->bit_rate == av->bit_rate) {
3311

    
3312
            switch(av->codec_type) {
3313
            case CODEC_TYPE_AUDIO:
3314
                if (av1->channels == av->channels &&
3315
                    av1->sample_rate == av->sample_rate)
3316
                    goto found;
3317
                break;
3318
            case CODEC_TYPE_VIDEO:
3319
                if (av1->width == av->width &&
3320
                    av1->height == av->height &&
3321
                    av1->time_base.den == av->time_base.den &&
3322
                    av1->time_base.num == av->time_base.num &&
3323
                    av1->gop_size == av->gop_size)
3324
                    goto found;
3325
                break;
3326
            default:
3327
                abort();
3328
            }
3329
        }
3330
    }
3331

    
3332
    fst = add_av_stream1(feed, av);
3333
    if (!fst)
3334
        return -1;
3335
    return feed->nb_streams - 1;
3336
 found:
3337
    return i;
3338
}
3339

    
3340
static void remove_stream(FFStream *stream)
3341
{
3342
    FFStream **ps;
3343
    ps = &first_stream;
3344
    while (*ps != NULL) {
3345
        if (*ps == stream)
3346
            *ps = (*ps)->next;
3347
        else
3348
            ps = &(*ps)->next;
3349
    }
3350
}
3351

    
3352
/* specific mpeg4 handling : we extract the raw parameters */
3353
static void extract_mpeg4_header(AVFormatContext *infile)
3354
{
3355
    int mpeg4_count, i, size;
3356
    AVPacket pkt;
3357
    AVStream *st;
3358
    const uint8_t *p;
3359

    
3360
    mpeg4_count = 0;
3361
    for(i=0;i<infile->nb_streams;i++) {
3362
        st = infile->streams[i];
3363
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3364
            st->codec->extradata_size == 0) {
3365
            mpeg4_count++;
3366
        }
3367
    }
3368
    if (!mpeg4_count)
3369
        return;
3370

    
3371
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3372
    while (mpeg4_count > 0) {
3373
        if (av_read_packet(infile, &pkt) < 0)
3374
            break;
3375
        st = infile->streams[pkt.stream_index];
3376
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3377
            st->codec->extradata_size == 0) {
3378
            av_freep(&st->codec->extradata);
3379
            /* fill extradata with the header */
3380
            /* XXX: we make hard suppositions here ! */
3381
            p = pkt.data;
3382
            while (p < pkt.data + pkt.size - 4) {
3383
                /* stop when vop header is found */
3384
                if (p[0] == 0x00 && p[1] == 0x00 &&
3385
                    p[2] == 0x01 && p[3] == 0xb6) {
3386
                    size = p - pkt.data;
3387
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3388
                    st->codec->extradata = av_malloc(size);
3389
                    st->codec->extradata_size = size;
3390
                    memcpy(st->codec->extradata, pkt.data, size);
3391
                    break;
3392
                }
3393
                p++;
3394
            }
3395
            mpeg4_count--;
3396
        }
3397
        av_free_packet(&pkt);
3398
    }
3399
}
3400

    
3401
/* compute the needed AVStream for each file */
3402
static void build_file_streams(void)
3403
{
3404
    FFStream *stream, *stream_next;
3405
    AVFormatContext *infile;
3406
    int i, ret;
3407

    
3408
    /* gather all streams */
3409
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3410
        stream_next = stream->next;
3411
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3412
            !stream->feed) {
3413
            /* the stream comes from a file */
3414
            /* try to open the file */
3415
            /* open stream */
3416
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3417
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3418
                /* specific case : if transport stream output to RTP,
3419
                   we use a raw transport stream reader */
3420
                stream->ap_in->mpeg2ts_raw = 1;
3421
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3422
            }
3423

    
3424
            http_log("Opening file '%s'\n", stream->feed_filename);
3425
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3426
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3427
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3428
                /* remove stream (no need to spend more time on it) */
3429
            fail:
3430
                remove_stream(stream);
3431
            } else {
3432
                /* find all the AVStreams inside and reference them in
3433
                   'stream' */
3434
                if (av_find_stream_info(infile) < 0) {
3435
                    http_log("Could not find codec parameters from '%s'\n",
3436
                             stream->feed_filename);
3437
                    av_close_input_file(infile);
3438
                    goto fail;
3439
                }
3440
                extract_mpeg4_header(infile);
3441

    
3442
                for(i=0;i<infile->nb_streams;i++)
3443
                    add_av_stream1(stream, infile->streams[i]->codec);
3444

    
3445
                av_close_input_file(infile);
3446
            }
3447
        }
3448
    }
3449
}
3450

    
3451
/* compute the needed AVStream for each feed */
3452
static void build_feed_streams(void)
3453
{
3454
    FFStream *stream, *feed;
3455
    int i;
3456

    
3457
    /* gather all streams */
3458
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3459
        feed = stream->feed;
3460
        if (feed) {
3461
            if (!stream->is_feed) {
3462
                /* we handle a stream coming from a feed */
3463
                for(i=0;i<stream->nb_streams;i++)
3464
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3465
            }
3466
        }
3467
    }
3468

    
3469
    /* gather all streams */
3470
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3471
        feed = stream->feed;
3472
        if (feed) {
3473
            if (stream->is_feed) {
3474
                for(i=0;i<stream->nb_streams;i++)
3475
                    stream->feed_streams[i] = i;
3476
            }
3477
        }
3478
    }
3479

    
3480
    /* create feed files if needed */
3481
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3482
        int fd;
3483

    
3484
        if (url_exist(feed->feed_filename)) {
3485
            /* See if it matches */
3486
            AVFormatContext *s;
3487
            int matches = 0;
3488

    
3489
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3490
                /* Now see if it matches */
3491
                if (s->nb_streams == feed->nb_streams) {
3492
                    matches = 1;
3493
                    for(i=0;i<s->nb_streams;i++) {
3494
                        AVStream *sf, *ss;
3495
                        sf = feed->streams[i];
3496
                        ss = s->streams[i];
3497

    
3498
                        if (sf->index != ss->index ||
3499
                            sf->id != ss->id) {
3500
                            http_log("Index & Id do not match for stream %d (%s)\n",
3501
                                   i, feed->feed_filename);
3502
                            matches = 0;
3503
                        } else {
3504
                            AVCodecContext *ccf, *ccs;
3505

    
3506
                            ccf = sf->codec;
3507
                            ccs = ss->codec;
3508
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3509

    
3510
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3511
                                http_log("Codecs do not match for stream %d\n", i);
3512
                                matches = 0;
3513
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3514
                                http_log("Codec bitrates do not match for stream %d\n", i);
3515
                                matches = 0;
3516
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3517
                                if (CHECK_CODEC(time_base.den) ||
3518
                                    CHECK_CODEC(time_base.num) ||
3519
                                    CHECK_CODEC(width) ||
3520
                                    CHECK_CODEC(height)) {
3521
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3522
                                    matches = 0;
3523
                                }
3524
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3525
                                if (CHECK_CODEC(sample_rate) ||
3526
                                    CHECK_CODEC(channels) ||
3527
                                    CHECK_CODEC(frame_size)) {
3528
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3529
                                    matches = 0;
3530
                                }
3531
                            } else {
3532
                                http_log("Unknown codec type\n");
3533
                                matches = 0;
3534
                            }
3535
                        }
3536
                        if (!matches)
3537
                            break;
3538
                    }
3539
                } else
3540
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3541
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3542

    
3543
                av_close_input_file(s);
3544
            } else
3545
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3546
                        feed->feed_filename);
3547

    
3548
            if (!matches) {
3549
                if (feed->readonly) {
3550
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3551
                        feed->feed_filename);
3552
                    exit(1);
3553
                }
3554
                unlink(feed->feed_filename);
3555
            }
3556
        }
3557
        if (!url_exist(feed->feed_filename)) {
3558
            AVFormatContext s1 = {0}, *s = &s1;
3559

    
3560
            if (feed->readonly) {
3561
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3562
                    feed->feed_filename);
3563
                exit(1);
3564
            }
3565

    
3566
            /* only write the header of the ffm file */
3567
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3568
                http_log("Could not open output feed file '%s'\n",
3569
                         feed->feed_filename);
3570
                exit(1);
3571
            }
3572
            s->oformat = feed->fmt;
3573
            s->nb_streams = feed->nb_streams;
3574
            for(i=0;i<s->nb_streams;i++) {
3575
                AVStream *st;
3576
                st = feed->streams[i];
3577
                s->streams[i] = st;
3578
            }
3579
            av_set_parameters(s, NULL);
3580
            if (av_write_header(s) < 0) {
3581
                http_log("Container doesn't supports the required parameters\n");
3582
                exit(1);
3583
            }
3584
            /* XXX: need better api */
3585
            av_freep(&s->priv_data);
3586
            url_fclose(s->pb);
3587
        }
3588
        /* get feed size and write index */
3589
        fd = open(feed->feed_filename, O_RDONLY);
3590
        if (fd < 0) {
3591
            http_log("Could not open output feed file '%s'\n",
3592
                    feed->feed_filename);
3593
            exit(1);
3594
        }
3595

    
3596
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3597
        feed->feed_size = lseek(fd, 0, SEEK_END);
3598
        /* ensure that we do not wrap before the end of file */
3599
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3600
            feed->feed_max_size = feed->feed_size;
3601

    
3602
        close(fd);
3603
    }
3604
}
3605

    
3606
/* compute the bandwidth used by each stream */
3607
static void compute_bandwidth(void)
3608
{
3609
    unsigned bandwidth;
3610
    int i;
3611
    FFStream *stream;
3612

    
3613
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3614
        bandwidth = 0;
3615
        for(i=0;i<stream->nb_streams;i++) {
3616
            AVStream *st = stream->streams[i];
3617
            switch(st->codec->codec_type) {
3618
            case CODEC_TYPE_AUDIO:
3619
            case CODEC_TYPE_VIDEO:
3620
                bandwidth += st->codec->bit_rate;
3621
                break;
3622
            default:
3623
                break;
3624
            }
3625
        }
3626
        stream->bandwidth = (bandwidth + 999) / 1000;
3627
    }
3628
}
3629

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

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

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

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

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

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

    
3691

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

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

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

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

    
3712
    return p->id;
3713
}
3714

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

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

    
3722
    return p->id;
3723
}
3724

    
3725
/* simplistic plugin support */
3726

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

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

    
3747
    init_func();
3748
}
3749
#endif
3750

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

    
3761
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3762
                                             const char *mime_type)
3763
{
3764
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3765

    
3766
    if (fmt) {
3767
        AVOutputFormat *stream_fmt;
3768
        char stream_format_name[64];
3769

    
3770
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3771
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3772

    
3773
        if (stream_fmt)
3774
            fmt = stream_fmt;
3775
    }
3776

    
3777
    return fmt;
3778
}
3779

    
3780
static int parse_ffconfig(const char *filename)
3781
{
3782
    FILE *f;
3783
    char line[1024];
3784
    char cmd[64];
3785
    char arg[1024];
3786
    const char *p;
3787
    int val, errors, line_num;
3788
    FFStream **last_stream, *stream, *redirect;
3789
    FFStream **last_feed, *feed, *s;
3790
    AVCodecContext audio_enc, video_enc;
3791
    enum CodecID audio_id, video_id;
3792

    
3793
    f = fopen(filename, "r");
3794
    if (!f) {
3795
        perror(filename);
3796
        return -1;
3797
    }
3798

    
3799
    errors = 0;
3800
    line_num = 0;
3801
    first_stream = NULL;
3802
    last_stream = &first_stream;
3803
    first_feed = NULL;
3804
    last_feed = &first_feed;
3805
    stream = NULL;
3806
    feed = NULL;
3807
    redirect = NULL;
3808
    audio_id = CODEC_ID_NONE;
3809
    video_id = CODEC_ID_NONE;
3810
    for(;;) {
3811
        if (fgets(line, sizeof(line), f) == NULL)
3812
            break;
3813
        line_num++;
3814
        p = line;
3815
        while (isspace(*p))
3816
            p++;
3817
        if (*p == '\0' || *p == '#')
3818
            continue;
3819

    
3820
        get_arg(cmd, sizeof(cmd), &p);
3821

    
3822
        if (!strcasecmp(cmd, "Port")) {
3823
            get_arg(arg, sizeof(arg), &p);
3824
            val = atoi(arg);
3825
            if (val < 1 || val > 65536) {
3826
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3827
                        filename, line_num, arg);
3828
                errors++;
3829
            }
3830
            my_http_addr.sin_port = htons(val);
3831
        } else if (!strcasecmp(cmd, "BindAddress")) {
3832
            get_arg(arg, sizeof(arg), &p);
3833
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3834
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3835
                        filename, line_num, arg);
3836
                errors++;
3837
            }
3838
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3839
            ffserver_daemon = 0;
3840
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3841
            get_arg(arg, sizeof(arg), &p);
3842
            val = atoi(arg);
3843
            if (val < 1 || val > 65536) {
3844
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3845
                        filename, line_num, arg);
3846
                errors++;
3847
            }
3848
            my_rtsp_addr.sin_port = htons(atoi(arg));
3849
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3850
            get_arg(arg, sizeof(arg), &p);
3851
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3852
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3853
                        filename, line_num, arg);
3854
                errors++;
3855
            }
3856
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3857
            get_arg(arg, sizeof(arg), &p);
3858
            val = atoi(arg);
3859
            if (val < 1 || val > 65536) {
3860
                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3861
                        filename, line_num, arg);
3862
                errors++;
3863
            }
3864
            nb_max_http_connections = val;
3865
        } else if (!strcasecmp(cmd, "MaxClients")) {
3866
            get_arg(arg, sizeof(arg), &p);
3867
            val = atoi(arg);
3868
            if (val < 1 || val > nb_max_http_connections) {
3869
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3870
                        filename, line_num, arg);
3871
                errors++;
3872
            } else {
3873
                nb_max_connections = val;
3874
            }
3875
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3876
            int64_t llval;
3877
            get_arg(arg, sizeof(arg), &p);
3878
            llval = atoll(arg);
3879
            if (llval < 10 || llval > 10000000) {
3880
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3881
                        filename, line_num, arg);
3882
                errors++;
3883
            } else
3884
                max_bandwidth = llval;
3885
        } else if (!strcasecmp(cmd, "CustomLog")) {
3886
            if (!ffserver_debug)
3887
                get_arg(logfilename, sizeof(logfilename), &p);
3888
        } else if (!strcasecmp(cmd, "<Feed")) {
3889
            /*********************************************/
3890
            /* Feed related options */
3891
            char *q;
3892
            if (stream || feed) {
3893
                fprintf(stderr, "%s:%d: Already in a tag\n",
3894
                        filename, line_num);
3895
            } else {
3896
                feed = av_mallocz(sizeof(FFStream));
3897
                get_arg(feed->filename, sizeof(feed->filename), &p);
3898
                q = strrchr(feed->filename, '>');
3899
                if (*q)
3900
                    *q = '\0';
3901

    
3902
                for (s = first_feed; s; s = s->next) {
3903
                    if (!strcmp(feed->filename, s->filename)) {
3904
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3905
                                filename, line_num, s->filename);
3906
                        errors++;
3907
                    }
3908
                }
3909

    
3910
                feed->fmt = av_guess_format("ffm", NULL, NULL);
3911
                /* defaut feed file */
3912
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3913
                         "/tmp/%s.ffm", feed->filename);
3914
                feed->feed_max_size = 5 * 1024 * 1024;
3915
                feed->is_feed = 1;
3916
                feed->feed = feed; /* self feeding :-) */
3917

    
3918
                /* add in stream list */
3919
                *last_stream = feed;
3920
                last_stream = &feed->next;
3921
                /* add in feed list */
3922
                *last_feed = feed;
3923
                last_feed = &feed->next_feed;
3924
            }
3925
        } else if (!strcasecmp(cmd, "Launch")) {
3926
            if (feed) {
3927
                int i;
3928

    
3929
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3930

    
3931
                for (i = 0; i < 62; i++) {
3932
                    get_arg(arg, sizeof(arg), &p);
3933
                    if (!arg[0])
3934
                        break;
3935

    
3936
                    feed->child_argv[i] = av_strdup(arg);
3937
                }
3938

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

    
3941
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3942
                    "http://%s:%d/%s",
3943
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3944
                    inet_ntoa(my_http_addr.sin_addr),
3945
                    ntohs(my_http_addr.sin_port), feed->filename);
3946
            }
3947
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3948
            if (feed) {
3949
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3950
                feed->readonly = 1;
3951
            } else if (stream) {
3952
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3953
            }
3954
        } else if (!strcasecmp(cmd, "File")) {
3955
            if (feed) {
3956
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3957
            } else if (stream)
3958
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3959
        } else if (!strcasecmp(cmd, "Truncate")) {
3960
            if (feed) {
3961
                get_arg(arg, sizeof(arg), &p);
3962
                feed->truncate = strtod(arg, NULL);
3963
            }
3964
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3965
            if (feed) {
3966
                char *p1;
3967
                double fsize;
3968

    
3969
                get_arg(arg, sizeof(arg), &p);
3970
                p1 = arg;
3971
                fsize = strtod(p1, &p1);
3972
                switch(toupper(*p1)) {
3973
                case 'K':
3974
                    fsize *= 1024;
3975
                    break;
3976
                case 'M':
3977
                    fsize *= 1024 * 1024;
3978
                    break;
3979
                case 'G':
3980
                    fsize *= 1024 * 1024 * 1024;
3981
                    break;
3982
                }
3983
                feed->feed_max_size = (int64_t)fsize;
3984
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
3985
                    fprintf(stderr, "%s:%d: Feed max file size is too small, "
3986
                            "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
3987
                    errors++;
3988
                }
3989
            }
3990
        } else if (!strcasecmp(cmd, "</Feed>")) {
3991
            if (!feed) {
3992
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3993
                        filename, line_num);
3994
                errors++;
3995
            }
3996
            feed = NULL;
3997
        } else if (!strcasecmp(cmd, "<Stream")) {
3998
            /*********************************************/
3999
            /* Stream related options */
4000
            char *q;
4001
            if (stream || feed) {
4002
                fprintf(stderr, "%s:%d: Already in a tag\n",
4003
                        filename, line_num);
4004
            } else {
4005
                FFStream *s;
4006
                const AVClass *class;
4007
                stream = av_mallocz(sizeof(FFStream));
4008
                get_arg(stream->filename, sizeof(stream->filename), &p);
4009
                q = strrchr(stream->filename, '>');
4010
                if (*q)
4011
                    *q = '\0';
4012

    
4013
                for (s = first_stream; s; s = s->next) {
4014
                    if (!strcmp(stream->filename, s->filename)) {
4015
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
4016
                                filename, line_num, s->filename);
4017
                        errors++;
4018
                    }
4019
                }
4020

    
4021
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4022
                /* fetch avclass so AVOption works
4023
                 * FIXME try to use avcodec_get_context_defaults2
4024
                 * without changing defaults too much */
4025
                avcodec_get_context_defaults(&video_enc);
4026
                class = video_enc.av_class;
4027
                memset(&audio_enc, 0, sizeof(AVCodecContext));
4028
                memset(&video_enc, 0, sizeof(AVCodecContext));
4029
                audio_enc.av_class = class;
4030
                video_enc.av_class = class;
4031
                audio_id = CODEC_ID_NONE;
4032
                video_id = CODEC_ID_NONE;
4033
                if (stream->fmt) {
4034
                    audio_id = stream->fmt->audio_codec;
4035
                    video_id = stream->fmt->video_codec;
4036
                }
4037

    
4038
                *last_stream = stream;
4039
                last_stream = &stream->next;
4040
            }
4041
        } else if (!strcasecmp(cmd, "Feed")) {
4042
            get_arg(arg, sizeof(arg), &p);
4043
            if (stream) {
4044
                FFStream *sfeed;
4045

    
4046
                sfeed = first_feed;
4047
                while (sfeed != NULL) {
4048
                    if (!strcmp(sfeed->filename, arg))
4049
                        break;
4050
                    sfeed = sfeed->next_feed;
4051
                }
4052
                if (!sfeed)
4053
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4054
                            filename, line_num, arg);
4055
                else
4056
                    stream->feed = sfeed;
4057
            }
4058
        } else if (!strcasecmp(cmd, "Format")) {
4059
            get_arg(arg, sizeof(arg), &p);
4060
            if (stream) {
4061
                if (!strcmp(arg, "status")) {
4062
                    stream->stream_type = STREAM_TYPE_STATUS;
4063
                    stream->fmt = NULL;
4064
                } else {
4065
                    stream->stream_type = STREAM_TYPE_LIVE;
4066
                    /* jpeg cannot be used here, so use single frame jpeg */
4067
                    if (!strcmp(arg, "jpeg"))
4068
                        strcpy(arg, "mjpeg");
4069
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4070
                    if (!stream->fmt) {
4071
                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4072
                                filename, line_num, arg);
4073
                        errors++;
4074
                    }
4075
                }
4076
                if (stream->fmt) {
4077
                    audio_id = stream->fmt->audio_codec;
4078
                    video_id = stream->fmt->video_codec;
4079
                }
4080
            }
4081
        } else if (!strcasecmp(cmd, "InputFormat")) {
4082
            get_arg(arg, sizeof(arg), &p);
4083
            if (stream) {
4084
                stream->ifmt = av_find_input_format(arg);
4085
                if (!stream->ifmt) {
4086
                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4087
                            filename, line_num, arg);
4088
                }
4089
            }
4090
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4091
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4092
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4093
            } else {
4094
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4095
                            filename, line_num);
4096
                errors++;
4097
            }
4098
        } else if (!strcasecmp(cmd, "Author")) {
4099
            if (stream)
4100
                get_arg(stream->author, sizeof(stream->author), &p);
4101
        } else if (!strcasecmp(cmd, "Comment")) {
4102
            if (stream)
4103
                get_arg(stream->comment, sizeof(stream->comment), &p);
4104
        } else if (!strcasecmp(cmd, "Copyright")) {
4105
            if (stream)
4106
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4107
        } else if (!strcasecmp(cmd, "Title")) {
4108
            if (stream)
4109
                get_arg(stream->title, sizeof(stream->title), &p);
4110
        } else if (!strcasecmp(cmd, "Preroll")) {
4111
            get_arg(arg, sizeof(arg), &p);
4112
            if (stream)
4113
                stream->prebuffer = atof(arg) * 1000;
4114
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4115
            if (stream)
4116
                stream->send_on_key = 1;
4117
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4118
            get_arg(arg, sizeof(arg), &p);
4119
            audio_id = opt_audio_codec(arg);
4120
            if (audio_id == CODEC_ID_NONE) {
4121
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4122
                        filename, line_num, arg);
4123
                errors++;
4124
            }
4125
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4126
            get_arg(arg, sizeof(arg), &p);
4127
            video_id = opt_video_codec(arg);
4128
            if (video_id == CODEC_ID_NONE) {
4129
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4130
                        filename, line_num, arg);
4131
                errors++;
4132
            }
4133
        } else if (!strcasecmp(cmd, "MaxTime")) {
4134
            get_arg(arg, sizeof(arg), &p);
4135
            if (stream)
4136
                stream->max_time = atof(arg) * 1000;
4137
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4138
            get_arg(arg, sizeof(arg), &p);
4139
            if (stream)
4140
                audio_enc.bit_rate = atoi(arg) * 1000;
4141
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4142
            get_arg(arg, sizeof(arg), &p);
4143
            if (stream)
4144
                audio_enc.channels = atoi(arg);
4145
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4146
            get_arg(arg, sizeof(arg), &p);
4147
            if (stream)
4148
                audio_enc.sample_rate = atoi(arg);
4149
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4150
            get_arg(arg, sizeof(arg), &p);
4151
            if (stream) {
4152
//                audio_enc.quality = atof(arg) * 1000;
4153
            }
4154
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4155
            if (stream) {
4156
                int minrate, maxrate;
4157

    
4158
                get_arg(arg, sizeof(arg), &p);
4159

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

    
4322
            get_arg(arg, sizeof(arg), &p);
4323
            if (strcasecmp(arg, "allow") == 0)
4324
                acl.action = IP_ALLOW;
4325
            else if (strcasecmp(arg, "deny") == 0)
4326
                acl.action = IP_DENY;
4327
            else {
4328
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4329
                        filename, line_num, arg);
4330
                errors++;
4331
            }
4332

    
4333
            get_arg(arg, sizeof(arg), &p);
4334

    
4335
            if (resolve_host(&acl.first, arg) != 0) {
4336
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4337
                        filename, line_num, arg);
4338
                errors++;
4339
            } else
4340
                acl.last = acl.first;
4341

    
4342
            get_arg(arg, sizeof(arg), &p);
4343

    
4344
            if (arg[0]) {
4345
                if (resolve_host(&acl.last, arg) != 0) {
4346
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4347
                            filename, line_num, arg);
4348
                    errors++;
4349
                }
4350
            }
4351

    
4352
            if (!errors) {
4353
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4354
                IPAddressACL **naclp = 0;
4355

    
4356
                acl.next = 0;
4357
                *nacl = acl;
4358

    
4359
                if (stream)
4360
                    naclp = &stream->acl;
4361
                else if (feed)
4362
                    naclp = &feed->acl;
4363
                else {
4364
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4365
                            filename, line_num);
4366
                    errors++;
4367
                }
4368

    
4369
                if (naclp) {
4370
                    while (*naclp)
4371
                        naclp = &(*naclp)->next;
4372

    
4373
                    *naclp = nacl;
4374
                }
4375
            }
4376
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4377
            get_arg(arg, sizeof(arg), &p);
4378
            if (stream) {
4379
                av_freep(&stream->rtsp_option);
4380
                stream->rtsp_option = av_strdup(arg);
4381
            }
4382
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4383
            get_arg(arg, sizeof(arg), &p);
4384
            if (stream) {
4385
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4386
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4387
                            filename, line_num, arg);
4388
                    errors++;
4389
                }
4390
                stream->is_multicast = 1;
4391
                stream->loop = 1; /* default is looping */
4392
            }
4393
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4394
            get_arg(arg, sizeof(arg), &p);
4395
            if (stream)
4396
                stream->multicast_port = atoi(arg);
4397
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4398
            get_arg(arg, sizeof(arg), &p);
4399
            if (stream)
4400
                stream->multicast_ttl = atoi(arg);
4401
        } else if (!strcasecmp(cmd, "NoLoop")) {
4402
            if (stream)
4403
                stream->loop = 0;
4404
        } else if (!strcasecmp(cmd, "</Stream>")) {
4405
            if (!stream) {
4406
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4407
                        filename, line_num);
4408
                errors++;
4409
            } else {
4410
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4411
                    if (audio_id != CODEC_ID_NONE) {
4412
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4413
                        audio_enc.codec_id = audio_id;
4414
                        add_codec(stream, &audio_enc);
4415
                    }
4416
                    if (video_id != CODEC_ID_NONE) {
4417
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4418
                        video_enc.codec_id = video_id;
4419
                        add_codec(stream, &video_enc);
4420
                    }
4421
                }
4422
                stream = NULL;
4423
            }
4424
        } else if (!strcasecmp(cmd, "<Redirect")) {
4425
            /*********************************************/
4426
            char *q;
4427
            if (stream || feed || redirect) {
4428
                fprintf(stderr, "%s:%d: Already in a tag\n",
4429
                        filename, line_num);
4430
                errors++;
4431
            } else {
4432
                redirect = av_mallocz(sizeof(FFStream));
4433
                *last_stream = redirect;
4434
                last_stream = &redirect->next;
4435

    
4436
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4437
                q = strrchr(redirect->filename, '>');
4438
                if (*q)
4439
                    *q = '\0';
4440
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4441
            }
4442
        } else if (!strcasecmp(cmd, "URL")) {
4443
            if (redirect)
4444
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4445
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4446
            if (!redirect) {
4447
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4448
                        filename, line_num);
4449
                errors++;
4450
            } else {
4451
                if (!redirect->feed_filename[0]) {
4452
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4453
                            filename, line_num);
4454
                    errors++;
4455
                }
4456
                redirect = NULL;
4457
            }
4458
        } else if (!strcasecmp(cmd, "LoadModule")) {
4459
            get_arg(arg, sizeof(arg), &p);
4460
#if HAVE_DLOPEN
4461
            load_module(arg);
4462
#else
4463
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4464
                    filename, line_num, arg);
4465
            errors++;
4466
#endif
4467
        } else {
4468
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4469
                    filename, line_num, cmd);
4470
        }
4471
    }
4472

    
4473
    fclose(f);
4474
    if (errors)
4475
        return -1;
4476
    else
4477
        return 0;
4478
}
4479

    
4480
static void handle_child_exit(int sig)
4481
{
4482
    pid_t pid;
4483
    int status;
4484

    
4485
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4486
        FFStream *feed;
4487

    
4488
        for (feed = first_feed; feed; feed = feed->next) {
4489
            if (feed->pid == pid) {
4490
                int uptime = time(0) - feed->pid_start;
4491

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

    
4495
                if (uptime < 30)
4496
                    /* Turn off any more restarts */
4497
                    feed->child_argv = 0;
4498
            }
4499
        }
4500
    }
4501

    
4502
    need_to_start_children = 1;
4503
}
4504

    
4505
static void opt_debug(void)
4506
{
4507
    ffserver_debug = 1;
4508
    ffserver_daemon = 0;
4509
    logfilename[0] = '-';
4510
}
4511

    
4512
static void show_help(void)
4513
{
4514
    printf("usage: ffserver [options]\n"
4515
           "Hyper fast multi format Audio/Video streaming server\n");
4516
    printf("\n");
4517
    show_help_options(options, "Main options:\n", 0, 0);
4518
}
4519

    
4520
static const OptionDef options[] = {
4521
#include "cmdutils_common_opts.h"
4522
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4523
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4524
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4525
    { NULL },
4526
};
4527

    
4528
int main(int argc, char **argv)
4529
{
4530
    struct sigaction sigact;
4531

    
4532
    av_register_all();
4533

    
4534
    show_banner();
4535

    
4536
    config_filename = "/etc/ffserver.conf";
4537

    
4538
    my_program_name = argv[0];
4539
    my_program_dir = getcwd(0, 0);
4540
    ffserver_daemon = 1;
4541

    
4542
    parse_options(argc, argv, options, NULL);
4543

    
4544
    unsetenv("http_proxy");             /* Kill the http_proxy */
4545

    
4546
    av_lfg_init(&random_state, ff_random_get_seed());
4547

    
4548
    memset(&sigact, 0, sizeof(sigact));
4549
    sigact.sa_handler = handle_child_exit;
4550
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4551
    sigaction(SIGCHLD, &sigact, 0);
4552

    
4553
    if (parse_ffconfig(config_filename) < 0) {
4554
        fprintf(stderr, "Incorrect config file - exiting.\n");
4555
        exit(1);
4556
    }
4557

    
4558
    /* open log file if needed */
4559
    if (logfilename[0] != '\0') {
4560
        if (!strcmp(logfilename, "-"))
4561
            logfile = stdout;
4562
        else
4563
            logfile = fopen(logfilename, "a");
4564
        av_log_set_callback(http_av_log);
4565
    }
4566

    
4567
    build_file_streams();
4568

    
4569
    build_feed_streams();
4570

    
4571
    compute_bandwidth();
4572

    
4573
    /* put the process in background and detach it from its TTY */
4574
    if (ffserver_daemon) {
4575
        int pid;
4576

    
4577
        pid = fork();
4578
        if (pid < 0) {
4579
            perror("fork");
4580
            exit(1);
4581
        } else if (pid > 0) {
4582
            /* parent : exit */
4583
            exit(0);
4584
        } else {
4585
            /* child */
4586
            setsid();
4587
            close(0);
4588
            open("/dev/null", O_RDWR);
4589
            if (strcmp(logfilename, "-") != 0) {
4590
                close(1);
4591
                dup(0);
4592
            }
4593
            close(2);
4594
            dup(0);
4595
        }
4596
    }
4597

    
4598
    /* signal init */
4599
    signal(SIGPIPE, SIG_IGN);
4600

    
4601
    if (ffserver_daemon)
4602
        chdir("/");
4603

    
4604
    if (http_server() < 0) {
4605
        http_log("Could not start server\n");
4606
        exit(1);
4607
    }
4608

    
4609
    return 0;
4610
}