Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 362b3bf7

History | View | Annotate | Download (147 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
#include "config.h"
23
#ifndef HAVE_CLOSESOCKET
24
#define closesocket close
25
#endif
26
#include <string.h>
27
#include <stdlib.h>
28
#include "avformat.h"
29
#include "rtsp.h"
30
#include "rtp.h"
31
#include "os_support.h"
32

    
33
#include <stdarg.h>
34
#include <unistd.h>
35
#include <fcntl.h>
36
#include <sys/ioctl.h>
37
#ifdef HAVE_POLL_H
38
#include <poll.h>
39
#endif
40
#include <errno.h>
41
#include <sys/time.h>
42
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
43
#include <time.h>
44
#include <sys/wait.h>
45
#include <signal.h>
46
#ifdef HAVE_DLFCN_H
47
#include <dlfcn.h>
48
#endif
49

    
50
#include "network.h"
51
#include "version.h"
52
#include "ffserver.h"
53
#include "random.h"
54
#include "avstring.h"
55
#include "cmdutils.h"
56

    
57
#undef exit
58

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

    
62
/* maximum number of simultaneous HTTP connections */
63
#define HTTP_MAX_CONNECTIONS 2000
64

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

    
75
    RTSPSTATE_WAIT_REQUEST,
76
    RTSPSTATE_SEND_REPLY,
77
    RTSPSTATE_SEND_PACKET,
78
};
79

    
80
const char *http_state[] = {
81
    "HTTP_WAIT_REQUEST",
82
    "HTTP_SEND_HEADER",
83

    
84
    "SEND_DATA_HEADER",
85
    "SEND_DATA",
86
    "SEND_DATA_TRAILER",
87
    "RECEIVE_DATA",
88
    "WAIT_FEED",
89
    "READY",
90

    
91
    "RTSP_WAIT_REQUEST",
92
    "RTSP_SEND_REPLY",
93
    "RTSP_SEND_PACKET",
94
};
95

    
96
#define IOBUFFER_INIT_SIZE 8192
97

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

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

    
104
typedef struct {
105
    int64_t count1, count2;
106
    int64_t time1, time2;
107
} DataRateData;
108

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

    
154
    /* RTSP state specific */
155
    uint8_t *pb_buffer; /* XXX: use that in all the code */
156
    ByteIOContext *pb;
157
    int seq; /* RTSP sequence number */
158

    
159
    /* RTP state specific */
160
    enum RTSPProtocol rtp_protocol;
161
    char session_id[32]; /* session id */
162
    AVFormatContext *rtp_ctx[MAX_STREAMS];
163

    
164
    /* RTP/UDP specific */
165
    URLContext *rtp_handles[MAX_STREAMS];
166

    
167
    /* RTP/TCP specific */
168
    struct HTTPContext *rtsp_c;
169
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170
} HTTPContext;
171

    
172
static AVFrame dummy_frame;
173

    
174
/* each generated stream is described here */
175
enum StreamType {
176
    STREAM_TYPE_LIVE,
177
    STREAM_TYPE_STATUS,
178
    STREAM_TYPE_REDIRECT,
179
};
180

    
181
enum IPAddressAction {
182
    IP_ALLOW = 1,
183
    IP_DENY,
184
};
185

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

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

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

    
242
typedef struct FeedData {
243
    long long data_count;
244
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
245
} FeedData;
246

    
247
static struct sockaddr_in my_http_addr;
248
static struct sockaddr_in my_rtsp_addr;
249

    
250
static char logfilename[1024];
251
static HTTPContext *first_http_ctx;
252
static FFStream *first_feed;   /* contains only feeds */
253
static FFStream *first_stream; /* contains all streams, including feeds */
254

    
255
static void new_connection(int server_fd, int is_rtsp);
256
static void close_connection(HTTPContext *c);
257

    
258
/* HTTP handling */
259
static int handle_connection(HTTPContext *c);
260
static int http_parse_request(HTTPContext *c);
261
static int http_send_data(HTTPContext *c);
262
static void compute_stats(HTTPContext *c);
263
static int open_input_stream(HTTPContext *c, const char *info);
264
static int http_start_receive_data(HTTPContext *c);
265
static int http_receive_data(HTTPContext *c);
266

    
267
/* RTSP handling */
268
static int rtsp_parse_request(HTTPContext *c);
269
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
270
static void rtsp_cmd_options(HTTPContext *c, const char *url);
271
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
272
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
273
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
274
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
275

    
276
/* SDP handling */
277
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
278
                                   struct in_addr my_ip);
279

    
280
/* RTP handling */
281
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
282
                                       FFStream *stream, const char *session_id,
283
                                       enum RTSPProtocol rtp_protocol);
284
static int rtp_new_av_stream(HTTPContext *c,
285
                             int stream_index, struct sockaddr_in *dest_addr,
286
                             HTTPContext *rtsp_c);
287

    
288
static const char *my_program_name;
289
static const char *my_program_dir;
290

    
291
static int ffserver_debug;
292
static int ffserver_daemon;
293
static int no_launch;
294
static int need_to_start_children;
295

    
296
static int nb_max_connections;
297
static int nb_connections;
298

    
299
static int max_bandwidth;
300
static int current_bandwidth;
301

    
302
static int64_t cur_time;           // Making this global saves on passing it around everywhere
303

    
304
static AVRandomState random_state;
305

    
306
static FILE *logfile = NULL;
307

    
308
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
309
{
310
    va_list ap;
311
    va_start(ap, fmt);
312

    
313
    if (logfile) {
314
        vfprintf(logfile, fmt, ap);
315
        fflush(logfile);
316
    }
317
    va_end(ap);
318
}
319

    
320
static char *ctime1(char *buf2)
321
{
322
    time_t ti;
323
    char *p;
324

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

    
334
static void log_connection(HTTPContext *c)
335
{
336
    char buf2[32];
337

    
338
    if (c->suppress_log)
339
        return;
340

    
341
    http_log("%s - - [%s] \"%s %s %s\" %d %"PRId64"\n",
342
             inet_ntoa(c->from_addr.sin_addr),
343
             ctime1(buf2), c->method, c->url,
344
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
345
}
346

    
347
static void update_datarate(DataRateData *drd, int64_t count)
348
{
349
    if (!drd->time1 && !drd->count1) {
350
        drd->time1 = drd->time2 = cur_time;
351
        drd->count1 = drd->count2 = count;
352
    } else if (cur_time - drd->time2 > 5000) {
353
        drd->time1 = drd->time2;
354
        drd->count1 = drd->count2;
355
        drd->time2 = cur_time;
356
        drd->count2 = count;
357
    }
358
}
359

    
360
/* In bytes per second */
361
static int compute_datarate(DataRateData *drd, int64_t count)
362
{
363
    if (cur_time == drd->time1)
364
        return 0;
365

    
366
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
367
}
368

    
369

    
370
static void start_children(FFStream *feed)
371
{
372
    if (no_launch)
373
        return;
374

    
375
    for (; feed; feed = feed->next) {
376
        if (feed->child_argv && !feed->pid) {
377
            feed->pid_start = time(0);
378

    
379
            feed->pid = fork();
380

    
381
            if (feed->pid < 0) {
382
                fprintf(stderr, "Unable to create children\n");
383
                exit(1);
384
            }
385
            if (!feed->pid) {
386
                /* In child */
387
                char pathname[1024];
388
                char *slash;
389
                int i;
390

    
391
                for (i = 3; i < 256; i++)
392
                    close(i);
393

    
394
                if (!ffserver_debug) {
395
                    i = open("/dev/null", O_RDWR);
396
                    if (i)
397
                        dup2(i, 0);
398
                    dup2(i, 1);
399
                    dup2(i, 2);
400
                    if (i)
401
                        close(i);
402
                }
403

    
404
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
405

    
406
                slash = strrchr(pathname, '/');
407
                if (!slash)
408
                    slash = pathname;
409
                else
410
                    slash++;
411
                strcpy(slash, "ffmpeg");
412

    
413
                /* This is needed to make relative pathnames work */
414
                chdir(my_program_dir);
415

    
416
                signal(SIGPIPE, SIG_DFL);
417

    
418
                execvp(pathname, feed->child_argv);
419

    
420
                _exit(1);
421
            }
422
        }
423
    }
424
}
425

    
426
/* open a listening socket */
427
static int socket_open_listen(struct sockaddr_in *my_addr)
428
{
429
    int server_fd, tmp;
430

    
431
    server_fd = socket(AF_INET,SOCK_STREAM,0);
432
    if (server_fd < 0) {
433
        perror ("socket");
434
        return -1;
435
    }
436

    
437
    tmp = 1;
438
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
439

    
440
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
441
        char bindmsg[32];
442
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
443
        perror (bindmsg);
444
        closesocket(server_fd);
445
        return -1;
446
    }
447

    
448
    if (listen (server_fd, 5) < 0) {
449
        perror ("listen");
450
        closesocket(server_fd);
451
        return -1;
452
    }
453
    ff_socket_nonblock(server_fd, 1);
454

    
455
    return server_fd;
456
}
457

    
458
/* start all multicast streams */
459
static void start_multicast(void)
460
{
461
    FFStream *stream;
462
    char session_id[32];
463
    HTTPContext *rtp_c;
464
    struct sockaddr_in dest_addr;
465
    int default_port, stream_index;
466

    
467
    default_port = 6000;
468
    for(stream = first_stream; stream != NULL; stream = stream->next) {
469
        if (stream->is_multicast) {
470
            /* open the RTP connection */
471
            snprintf(session_id, sizeof(session_id), "%08x%08x",
472
                     av_random(&random_state), av_random(&random_state));
473

    
474
            /* choose a port if none given */
475
            if (stream->multicast_port == 0) {
476
                stream->multicast_port = default_port;
477
                default_port += 100;
478
            }
479

    
480
            dest_addr.sin_family = AF_INET;
481
            dest_addr.sin_addr = stream->multicast_ip;
482
            dest_addr.sin_port = htons(stream->multicast_port);
483

    
484
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
485
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
486
            if (!rtp_c)
487
                continue;
488

    
489
            if (open_input_stream(rtp_c, "") < 0) {
490
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
491
                        stream->filename);
492
                continue;
493
            }
494

    
495
            /* open each RTP stream */
496
            for(stream_index = 0; stream_index < stream->nb_streams;
497
                stream_index++) {
498
                dest_addr.sin_port = htons(stream->multicast_port +
499
                                           2 * stream_index);
500
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
501
                    fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n",
502
                            stream->filename, stream_index);
503
                    exit(1);
504
                }
505
            }
506

    
507
            /* change state to send data */
508
            rtp_c->state = HTTPSTATE_SEND_DATA;
509
        }
510
    }
511
}
512

    
513
/* main loop of the http server */
514
static int http_server(void)
515
{
516
    int server_fd, ret, rtsp_server_fd, delay, delay1;
517
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
518
    HTTPContext *c, *c_next;
519

    
520
    server_fd = socket_open_listen(&my_http_addr);
521
    if (server_fd < 0)
522
        return -1;
523

    
524
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
525
    if (rtsp_server_fd < 0)
526
        return -1;
527

    
528
    http_log("ffserver started.\n");
529

    
530
    start_children(first_feed);
531

    
532
    first_http_ctx = NULL;
533
    nb_connections = 0;
534

    
535
    start_multicast();
536

    
537
    for(;;) {
538
        poll_entry = poll_table;
539
        poll_entry->fd = server_fd;
540
        poll_entry->events = POLLIN;
541
        poll_entry++;
542

    
543
        poll_entry->fd = rtsp_server_fd;
544
        poll_entry->events = POLLIN;
545
        poll_entry++;
546

    
547
        /* wait for events on each HTTP handle */
548
        c = first_http_ctx;
549
        delay = 1000;
550
        while (c != NULL) {
551
            int fd;
552
            fd = c->fd;
553
            switch(c->state) {
554
            case HTTPSTATE_SEND_HEADER:
555
            case RTSPSTATE_SEND_REPLY:
556
            case RTSPSTATE_SEND_PACKET:
557
                c->poll_entry = poll_entry;
558
                poll_entry->fd = fd;
559
                poll_entry->events = POLLOUT;
560
                poll_entry++;
561
                break;
562
            case HTTPSTATE_SEND_DATA_HEADER:
563
            case HTTPSTATE_SEND_DATA:
564
            case HTTPSTATE_SEND_DATA_TRAILER:
565
                if (!c->is_packetized) {
566
                    /* for TCP, we output as much as we can (may need to put a limit) */
567
                    c->poll_entry = poll_entry;
568
                    poll_entry->fd = fd;
569
                    poll_entry->events = POLLOUT;
570
                    poll_entry++;
571
                } else {
572
                    /* when ffserver is doing the timing, we work by
573
                       looking at which packet need to be sent every
574
                       10 ms */
575
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
576
                    if (delay1 < delay)
577
                        delay = delay1;
578
                }
579
                break;
580
            case HTTPSTATE_WAIT_REQUEST:
581
            case HTTPSTATE_RECEIVE_DATA:
582
            case HTTPSTATE_WAIT_FEED:
583
            case RTSPSTATE_WAIT_REQUEST:
584
                /* need to catch errors */
585
                c->poll_entry = poll_entry;
586
                poll_entry->fd = fd;
587
                poll_entry->events = POLLIN;/* Maybe this will work */
588
                poll_entry++;
589
                break;
590
            default:
591
                c->poll_entry = NULL;
592
                break;
593
            }
594
            c = c->next;
595
        }
596

    
597
        /* wait for an event on one connection. We poll at least every
598
           second to handle timeouts */
599
        do {
600
            ret = poll(poll_table, poll_entry - poll_table, delay);
601
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
602
                ff_neterrno() != FF_NETERROR(EINTR))
603
                return -1;
604
        } while (ret < 0);
605

    
606
        cur_time = av_gettime() / 1000;
607

    
608
        if (need_to_start_children) {
609
            need_to_start_children = 0;
610
            start_children(first_feed);
611
        }
612

    
613
        /* now handle the events */
614
        for(c = first_http_ctx; c != NULL; c = c_next) {
615
            c_next = c->next;
616
            if (handle_connection(c) < 0) {
617
                /* close and free the connection */
618
                log_connection(c);
619
                close_connection(c);
620
            }
621
        }
622

    
623
        poll_entry = poll_table;
624
        /* new HTTP connection request ? */
625
        if (poll_entry->revents & POLLIN)
626
            new_connection(server_fd, 0);
627
        poll_entry++;
628
        /* new RTSP connection request ? */
629
        if (poll_entry->revents & POLLIN)
630
            new_connection(rtsp_server_fd, 1);
631
    }
632
}
633

    
634
/* start waiting for a new HTTP/RTSP request */
635
static void start_wait_request(HTTPContext *c, int is_rtsp)
636
{
637
    c->buffer_ptr = c->buffer;
638
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
639

    
640
    if (is_rtsp) {
641
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
642
        c->state = RTSPSTATE_WAIT_REQUEST;
643
    } else {
644
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
645
        c->state = HTTPSTATE_WAIT_REQUEST;
646
    }
647
}
648

    
649
static void new_connection(int server_fd, int is_rtsp)
650
{
651
    struct sockaddr_in from_addr;
652
    int fd, len;
653
    HTTPContext *c = NULL;
654

    
655
    len = sizeof(from_addr);
656
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
657
                &len);
658
    if (fd < 0)
659
        return;
660
    ff_socket_nonblock(fd, 1);
661

    
662
    /* XXX: should output a warning page when coming
663
       close to the connection limit */
664
    if (nb_connections >= nb_max_connections)
665
        goto fail;
666

    
667
    /* add a new connection */
668
    c = av_mallocz(sizeof(HTTPContext));
669
    if (!c)
670
        goto fail;
671

    
672
    c->fd = fd;
673
    c->poll_entry = NULL;
674
    c->from_addr = from_addr;
675
    c->buffer_size = IOBUFFER_INIT_SIZE;
676
    c->buffer = av_malloc(c->buffer_size);
677
    if (!c->buffer)
678
        goto fail;
679

    
680
    c->next = first_http_ctx;
681
    first_http_ctx = c;
682
    nb_connections++;
683

    
684
    start_wait_request(c, is_rtsp);
685

    
686
    return;
687

    
688
 fail:
689
    if (c) {
690
        av_free(c->buffer);
691
        av_free(c);
692
    }
693
    closesocket(fd);
694
}
695

    
696
static void close_connection(HTTPContext *c)
697
{
698
    HTTPContext **cp, *c1;
699
    int i, nb_streams;
700
    AVFormatContext *ctx;
701
    URLContext *h;
702
    AVStream *st;
703

    
704
    /* remove connection from list */
705
    cp = &first_http_ctx;
706
    while ((*cp) != NULL) {
707
        c1 = *cp;
708
        if (c1 == c)
709
            *cp = c->next;
710
        else
711
            cp = &c1->next;
712
    }
713

    
714
    /* remove references, if any (XXX: do it faster) */
715
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
716
        if (c1->rtsp_c == c)
717
            c1->rtsp_c = NULL;
718
    }
719

    
720
    /* remove connection associated resources */
721
    if (c->fd >= 0)
722
        closesocket(c->fd);
723
    if (c->fmt_in) {
724
        /* close each frame parser */
725
        for(i=0;i<c->fmt_in->nb_streams;i++) {
726
            st = c->fmt_in->streams[i];
727
            if (st->codec->codec)
728
                avcodec_close(st->codec);
729
        }
730
        av_close_input_file(c->fmt_in);
731
    }
732

    
733
    /* free RTP output streams if any */
734
    nb_streams = 0;
735
    if (c->stream)
736
        nb_streams = c->stream->nb_streams;
737

    
738
    for(i=0;i<nb_streams;i++) {
739
        ctx = c->rtp_ctx[i];
740
        if (ctx) {
741
            av_write_trailer(ctx);
742
            av_free(ctx);
743
        }
744
        h = c->rtp_handles[i];
745
        if (h)
746
            url_close(h);
747
    }
748

    
749
    ctx = &c->fmt_ctx;
750

    
751
    if (!c->last_packet_sent) {
752
        if (ctx->oformat) {
753
            /* prepare header */
754
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
755
                av_write_trailer(ctx);
756
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
757
            }
758
        }
759
    }
760

    
761
    for(i=0; i<ctx->nb_streams; i++)
762
        av_free(ctx->streams[i]);
763

    
764
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
765
        current_bandwidth -= c->stream->bandwidth;
766

    
767
    /* signal that there is no feed if we are the feeder socket */
768
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
769
        c->stream->feed_opened = 0;
770
        close(c->feed_fd);
771
    }
772

    
773
    av_freep(&c->pb_buffer);
774
    av_freep(&c->packet_buffer);
775
    av_free(c->buffer);
776
    av_free(c);
777
    nb_connections--;
778
}
779

    
780
static int handle_connection(HTTPContext *c)
781
{
782
    int len, ret;
783

    
784
    switch(c->state) {
785
    case HTTPSTATE_WAIT_REQUEST:
786
    case RTSPSTATE_WAIT_REQUEST:
787
        /* timeout ? */
788
        if ((c->timeout - cur_time) < 0)
789
            return -1;
790
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
791
            return -1;
792

    
793
        /* no need to read if no events */
794
        if (!(c->poll_entry->revents & POLLIN))
795
            return 0;
796
        /* read the data */
797
    read_loop:
798
        len = recv(c->fd, c->buffer_ptr, 1, 0);
799
        if (len < 0) {
800
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
801
                ff_neterrno() != FF_NETERROR(EINTR))
802
                return -1;
803
        } else if (len == 0) {
804
            return -1;
805
        } else {
806
            /* search for end of request. */
807
            uint8_t *ptr;
808
            c->buffer_ptr += len;
809
            ptr = c->buffer_ptr;
810
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
811
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
812
                /* request found : parse it and reply */
813
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
814
                    ret = http_parse_request(c);
815
                } else {
816
                    ret = rtsp_parse_request(c);
817
                }
818
                if (ret < 0)
819
                    return -1;
820
            } else if (ptr >= c->buffer_end) {
821
                /* request too long: cannot do anything */
822
                return -1;
823
            } else goto read_loop;
824
        }
825
        break;
826

    
827
    case HTTPSTATE_SEND_HEADER:
828
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
829
            return -1;
830

    
831
        /* no need to write if no events */
832
        if (!(c->poll_entry->revents & POLLOUT))
833
            return 0;
834
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
835
        if (len < 0) {
836
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
837
                ff_neterrno() != FF_NETERROR(EINTR)) {
838
                /* error : close connection */
839
                av_freep(&c->pb_buffer);
840
                return -1;
841
            }
842
        } else {
843
            c->buffer_ptr += len;
844
            if (c->stream)
845
                c->stream->bytes_served += len;
846
            c->data_count += len;
847
            if (c->buffer_ptr >= c->buffer_end) {
848
                av_freep(&c->pb_buffer);
849
                /* if error, exit */
850
                if (c->http_error)
851
                    return -1;
852
                /* all the buffer was sent : synchronize to the incoming stream */
853
                c->state = HTTPSTATE_SEND_DATA_HEADER;
854
                c->buffer_ptr = c->buffer_end = c->buffer;
855
            }
856
        }
857
        break;
858

    
859
    case HTTPSTATE_SEND_DATA:
860
    case HTTPSTATE_SEND_DATA_HEADER:
861
    case HTTPSTATE_SEND_DATA_TRAILER:
862
        /* for packetized output, we consider we can always write (the
863
           input streams sets the speed). It may be better to verify
864
           that we do not rely too much on the kernel queues */
865
        if (!c->is_packetized) {
866
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
867
                return -1;
868

    
869
            /* no need to read if no events */
870
            if (!(c->poll_entry->revents & POLLOUT))
871
                return 0;
872
        }
873
        if (http_send_data(c) < 0)
874
            return -1;
875
        /* close connection if trailer sent */
876
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
877
            return -1;
878
        break;
879
    case HTTPSTATE_RECEIVE_DATA:
880
        /* no need to read if no events */
881
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
882
            return -1;
883
        if (!(c->poll_entry->revents & POLLIN))
884
            return 0;
885
        if (http_receive_data(c) < 0)
886
            return -1;
887
        break;
888
    case HTTPSTATE_WAIT_FEED:
889
        /* no need to read if no events */
890
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
891
            return -1;
892

    
893
        /* nothing to do, we'll be waken up by incoming feed packets */
894
        break;
895

    
896
    case RTSPSTATE_SEND_REPLY:
897
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
898
            av_freep(&c->pb_buffer);
899
            return -1;
900
        }
901
        /* no need to write if no events */
902
        if (!(c->poll_entry->revents & POLLOUT))
903
            return 0;
904
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
905
        if (len < 0) {
906
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
907
                ff_neterrno() != FF_NETERROR(EINTR)) {
908
                /* error : close connection */
909
                av_freep(&c->pb_buffer);
910
                return -1;
911
            }
912
        } else {
913
            c->buffer_ptr += len;
914
            c->data_count += len;
915
            if (c->buffer_ptr >= c->buffer_end) {
916
                /* all the buffer was sent : wait for a new request */
917
                av_freep(&c->pb_buffer);
918
                start_wait_request(c, 1);
919
            }
920
        }
921
        break;
922
    case RTSPSTATE_SEND_PACKET:
923
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
924
            av_freep(&c->packet_buffer);
925
            return -1;
926
        }
927
        /* no need to write if no events */
928
        if (!(c->poll_entry->revents & POLLOUT))
929
            return 0;
930
        len = send(c->fd, c->packet_buffer_ptr,
931
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
932
        if (len < 0) {
933
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
934
                ff_neterrno() != FF_NETERROR(EINTR)) {
935
                /* error : close connection */
936
                av_freep(&c->packet_buffer);
937
                return -1;
938
            }
939
        } else {
940
            c->packet_buffer_ptr += len;
941
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
942
                /* all the buffer was sent : wait for a new request */
943
                av_freep(&c->packet_buffer);
944
                c->state = RTSPSTATE_WAIT_REQUEST;
945
            }
946
        }
947
        break;
948
    case HTTPSTATE_READY:
949
        /* nothing to do */
950
        break;
951
    default:
952
        return -1;
953
    }
954
    return 0;
955
}
956

    
957
static int extract_rates(char *rates, int ratelen, const char *request)
958
{
959
    const char *p;
960

    
961
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
962
        if (strncasecmp(p, "Pragma:", 7) == 0) {
963
            const char *q = p + 7;
964

    
965
            while (*q && *q != '\n' && isspace(*q))
966
                q++;
967

    
968
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
969
                int stream_no;
970
                int rate_no;
971

    
972
                q += 20;
973

    
974
                memset(rates, 0xff, ratelen);
975

    
976
                while (1) {
977
                    while (*q && *q != '\n' && *q != ':')
978
                        q++;
979

    
980
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
981
                        break;
982

    
983
                    stream_no--;
984
                    if (stream_no < ratelen && stream_no >= 0)
985
                        rates[stream_no] = rate_no;
986

    
987
                    while (*q && *q != '\n' && !isspace(*q))
988
                        q++;
989
                }
990

    
991
                return 1;
992
            }
993
        }
994
        p = strchr(p, '\n');
995
        if (!p)
996
            break;
997

    
998
        p++;
999
    }
1000

    
1001
    return 0;
1002
}
1003

    
1004
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1005
{
1006
    int i;
1007
    int best_bitrate = 100000000;
1008
    int best = -1;
1009

    
1010
    for (i = 0; i < feed->nb_streams; i++) {
1011
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1012

    
1013
        if (feed_codec->codec_id != codec->codec_id ||
1014
            feed_codec->sample_rate != codec->sample_rate ||
1015
            feed_codec->width != codec->width ||
1016
            feed_codec->height != codec->height)
1017
            continue;
1018

    
1019
        /* Potential stream */
1020

    
1021
        /* We want the fastest stream less than bit_rate, or the slowest
1022
         * faster than bit_rate
1023
         */
1024

    
1025
        if (feed_codec->bit_rate <= bit_rate) {
1026
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1027
                best_bitrate = feed_codec->bit_rate;
1028
                best = i;
1029
            }
1030
        } else {
1031
            if (feed_codec->bit_rate < best_bitrate) {
1032
                best_bitrate = feed_codec->bit_rate;
1033
                best = i;
1034
            }
1035
        }
1036
    }
1037

    
1038
    return best;
1039
}
1040

    
1041
static int modify_current_stream(HTTPContext *c, char *rates)
1042
{
1043
    int i;
1044
    FFStream *req = c->stream;
1045
    int action_required = 0;
1046

    
1047
    /* Not much we can do for a feed */
1048
    if (!req->feed)
1049
        return 0;
1050

    
1051
    for (i = 0; i < req->nb_streams; i++) {
1052
        AVCodecContext *codec = req->streams[i]->codec;
1053

    
1054
        switch(rates[i]) {
1055
            case 0:
1056
                c->switch_feed_streams[i] = req->feed_streams[i];
1057
                break;
1058
            case 1:
1059
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1060
                break;
1061
            case 2:
1062
                /* Wants off or slow */
1063
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1064
#ifdef WANTS_OFF
1065
                /* This doesn't work well when it turns off the only stream! */
1066
                c->switch_feed_streams[i] = -2;
1067
                c->feed_streams[i] = -2;
1068
#endif
1069
                break;
1070
        }
1071

    
1072
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1073
            action_required = 1;
1074
    }
1075

    
1076
    return action_required;
1077
}
1078

    
1079

    
1080
static void do_switch_stream(HTTPContext *c, int i)
1081
{
1082
    if (c->switch_feed_streams[i] >= 0) {
1083
#ifdef PHILIP
1084
        c->feed_streams[i] = c->switch_feed_streams[i];
1085
#endif
1086

    
1087
        /* Now update the stream */
1088
    }
1089
    c->switch_feed_streams[i] = -1;
1090
}
1091

    
1092
/* XXX: factorize in utils.c ? */
1093
/* XXX: take care with different space meaning */
1094
static void skip_spaces(const char **pp)
1095
{
1096
    const char *p;
1097
    p = *pp;
1098
    while (*p == ' ' || *p == '\t')
1099
        p++;
1100
    *pp = p;
1101
}
1102

    
1103
static void get_word(char *buf, int buf_size, const char **pp)
1104
{
1105
    const char *p;
1106
    char *q;
1107

    
1108
    p = *pp;
1109
    skip_spaces(&p);
1110
    q = buf;
1111
    while (!isspace(*p) && *p != '\0') {
1112
        if ((q - buf) < buf_size - 1)
1113
            *q++ = *p;
1114
        p++;
1115
    }
1116
    if (buf_size > 0)
1117
        *q = '\0';
1118
    *pp = p;
1119
}
1120

    
1121
static int validate_acl(FFStream *stream, HTTPContext *c)
1122
{
1123
    enum IPAddressAction last_action = IP_DENY;
1124
    IPAddressACL *acl;
1125
    struct in_addr *src = &c->from_addr.sin_addr;
1126
    unsigned long src_addr = src->s_addr;
1127

    
1128
    for (acl = stream->acl; acl; acl = acl->next) {
1129
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1130
            return (acl->action == IP_ALLOW) ? 1 : 0;
1131
        last_action = acl->action;
1132
    }
1133

    
1134
    /* Nothing matched, so return not the last action */
1135
    return (last_action == IP_DENY) ? 1 : 0;
1136
}
1137

    
1138
/* compute the real filename of a file by matching it without its
1139
   extensions to all the stream filenames */
1140
static void compute_real_filename(char *filename, int max_size)
1141
{
1142
    char file1[1024];
1143
    char file2[1024];
1144
    char *p;
1145
    FFStream *stream;
1146

    
1147
    /* compute filename by matching without the file extensions */
1148
    av_strlcpy(file1, filename, sizeof(file1));
1149
    p = strrchr(file1, '.');
1150
    if (p)
1151
        *p = '\0';
1152
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1153
        av_strlcpy(file2, stream->filename, sizeof(file2));
1154
        p = strrchr(file2, '.');
1155
        if (p)
1156
            *p = '\0';
1157
        if (!strcmp(file1, file2)) {
1158
            av_strlcpy(filename, stream->filename, max_size);
1159
            break;
1160
        }
1161
    }
1162
}
1163

    
1164
enum RedirType {
1165
    REDIR_NONE,
1166
    REDIR_ASX,
1167
    REDIR_RAM,
1168
    REDIR_ASF,
1169
    REDIR_RTSP,
1170
    REDIR_SDP,
1171
};
1172

    
1173
/* parse http request and prepare header */
1174
static int http_parse_request(HTTPContext *c)
1175
{
1176
    char *p;
1177
    enum RedirType redir_type;
1178
    char cmd[32];
1179
    char info[1024], filename[1024];
1180
    char url[1024], *q;
1181
    char protocol[32];
1182
    char msg[1024];
1183
    const char *mime_type;
1184
    FFStream *stream;
1185
    int i;
1186
    char ratebuf[32];
1187
    char *useragent = 0;
1188

    
1189
    p = c->buffer;
1190
    get_word(cmd, sizeof(cmd), (const char **)&p);
1191
    av_strlcpy(c->method, cmd, sizeof(c->method));
1192

    
1193
    if (!strcmp(cmd, "GET"))
1194
        c->post = 0;
1195
    else if (!strcmp(cmd, "POST"))
1196
        c->post = 1;
1197
    else
1198
        return -1;
1199

    
1200
    get_word(url, sizeof(url), (const char **)&p);
1201
    av_strlcpy(c->url, url, sizeof(c->url));
1202

    
1203
    get_word(protocol, sizeof(protocol), (const char **)&p);
1204
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1205
        return -1;
1206

    
1207
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1208

    
1209
    if (ffserver_debug)
1210
        http_log("New connection: %s %s\n", cmd, url);
1211

    
1212
    /* find the filename and the optional info string in the request */
1213
    p = strchr(url, '?');
1214
    if (p) {
1215
        av_strlcpy(info, p, sizeof(info));
1216
        *p = '\0';
1217
    } else
1218
        info[0] = '\0';
1219

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

    
1222
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1223
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1224
            useragent = p + 11;
1225
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1226
                useragent++;
1227
            break;
1228
        }
1229
        p = strchr(p, '\n');
1230
        if (!p)
1231
            break;
1232

    
1233
        p++;
1234
    }
1235

    
1236
    redir_type = REDIR_NONE;
1237
    if (match_ext(filename, "asx")) {
1238
        redir_type = REDIR_ASX;
1239
        filename[strlen(filename)-1] = 'f';
1240
    } else if (match_ext(filename, "asf") &&
1241
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1242
        /* if this isn't WMP or lookalike, return the redirector file */
1243
        redir_type = REDIR_ASF;
1244
    } else if (match_ext(filename, "rpm,ram")) {
1245
        redir_type = REDIR_RAM;
1246
        strcpy(filename + strlen(filename)-2, "m");
1247
    } else if (match_ext(filename, "rtsp")) {
1248
        redir_type = REDIR_RTSP;
1249
        compute_real_filename(filename, sizeof(filename) - 1);
1250
    } else if (match_ext(filename, "sdp")) {
1251
        redir_type = REDIR_SDP;
1252
        compute_real_filename(filename, sizeof(filename) - 1);
1253
    }
1254

    
1255
    // "redirect" / request to index.html
1256
    if (!strlen(filename))
1257
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1258

    
1259
    stream = first_stream;
1260
    while (stream != NULL) {
1261
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1262
            break;
1263
        stream = stream->next;
1264
    }
1265
    if (stream == NULL) {
1266
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1267
        goto send_error;
1268
    }
1269

    
1270
    c->stream = stream;
1271
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1272
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1273

    
1274
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1275
        c->http_error = 301;
1276
        q = c->buffer;
1277
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1278
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1279
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1280
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1281
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1282
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1283
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1284

    
1285
        /* prepare output buffer */
1286
        c->buffer_ptr = c->buffer;
1287
        c->buffer_end = q;
1288
        c->state = HTTPSTATE_SEND_HEADER;
1289
        return 0;
1290
    }
1291

    
1292
    /* If this is WMP, get the rate information */
1293
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1294
        if (modify_current_stream(c, ratebuf)) {
1295
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1296
                if (c->switch_feed_streams[i] >= 0)
1297
                    do_switch_stream(c, i);
1298
            }
1299
        }
1300
    }
1301

    
1302
    /* If already streaming this feed, do not let start another feeder. */
1303
    if (stream->feed_opened) {
1304
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1305
        goto send_error;
1306
    }
1307

    
1308
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1309
        current_bandwidth += stream->bandwidth;
1310

    
1311
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1312
        c->http_error = 200;
1313
        q = c->buffer;
1314
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1315
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1316
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1320
            current_bandwidth, max_bandwidth);
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1322

    
1323
        /* prepare output buffer */
1324
        c->buffer_ptr = c->buffer;
1325
        c->buffer_end = q;
1326
        c->state = HTTPSTATE_SEND_HEADER;
1327
        return 0;
1328
    }
1329

    
1330
    if (redir_type != REDIR_NONE) {
1331
        char *hostinfo = 0;
1332

    
1333
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1334
            if (strncasecmp(p, "Host:", 5) == 0) {
1335
                hostinfo = p + 5;
1336
                break;
1337
            }
1338
            p = strchr(p, '\n');
1339
            if (!p)
1340
                break;
1341

    
1342
            p++;
1343
        }
1344

    
1345
        if (hostinfo) {
1346
            char *eoh;
1347
            char hostbuf[260];
1348

    
1349
            while (isspace(*hostinfo))
1350
                hostinfo++;
1351

    
1352
            eoh = strchr(hostinfo, '\n');
1353
            if (eoh) {
1354
                if (eoh[-1] == '\r')
1355
                    eoh--;
1356

    
1357
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1358
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1359
                    hostbuf[eoh - hostinfo] = 0;
1360

    
1361
                    c->http_error = 200;
1362
                    q = c->buffer;
1363
                    switch(redir_type) {
1364
                    case REDIR_ASX:
1365
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
1366
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1367
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1368
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
1369
                        //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
1370
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1371
                                hostbuf, filename, info);
1372
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
1373
                        break;
1374
                    case REDIR_RAM:
1375
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
1376
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
1377
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1378
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
1379
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
1380
                                hostbuf, filename, info);
1381
                        break;
1382
                    case REDIR_ASF:
1383
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
1384
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1385
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1386
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
1387
                        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
1388
                                hostbuf, filename, info);
1389
                        break;
1390
                    case REDIR_RTSP:
1391
                        {
1392
                            char hostname[256], *p;
1393
                            /* extract only hostname */
1394
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1395
                            p = strrchr(hostname, ':');
1396
                            if (p)
1397
                                *p = '\0';
1398
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1399
                            /* XXX: incorrect mime type ? */
1400
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
1401
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1402
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
1403
                                         hostname, ntohs(my_rtsp_addr.sin_port),
1404
                                         filename);
1405
                        }
1406
                        break;
1407
                    case REDIR_SDP:
1408
                        {
1409
                            uint8_t *sdp_data;
1410
                            int sdp_data_size, len;
1411
                            struct sockaddr_in my_addr;
1412

    
1413
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1414
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1415
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1416

    
1417
                            len = sizeof(my_addr);
1418
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1419

    
1420
                            /* XXX: should use a dynamic buffer */
1421
                            sdp_data_size = prepare_sdp_description(stream,
1422
                                                                    &sdp_data,
1423
                                                                    my_addr.sin_addr);
1424
                            if (sdp_data_size > 0) {
1425
                                memcpy(q, sdp_data, sdp_data_size);
1426
                                q += sdp_data_size;
1427
                                *q = '\0';
1428
                                av_free(sdp_data);
1429
                            }
1430
                        }
1431
                        break;
1432
                    default:
1433
                        abort();
1434
                        break;
1435
                    }
1436

    
1437
                    /* prepare output buffer */
1438
                    c->buffer_ptr = c->buffer;
1439
                    c->buffer_end = q;
1440
                    c->state = HTTPSTATE_SEND_HEADER;
1441
                    return 0;
1442
                }
1443
            }
1444
        }
1445

    
1446
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1447
        goto send_error;
1448
    }
1449

    
1450
    stream->conns_served++;
1451

    
1452
    /* XXX: add there authenticate and IP match */
1453

    
1454
    if (c->post) {
1455
        /* if post, it means a feed is being sent */
1456
        if (!stream->is_feed) {
1457
            /* However it might be a status report from WMP! Lets log the data
1458
             * as it might come in handy one day
1459
             */
1460
            char *logline = 0;
1461
            int client_id = 0;
1462

    
1463
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1464
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1465
                    logline = p;
1466
                    break;
1467
                }
1468
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1469
                    client_id = strtol(p + 18, 0, 10);
1470
                p = strchr(p, '\n');
1471
                if (!p)
1472
                    break;
1473

    
1474
                p++;
1475
            }
1476

    
1477
            if (logline) {
1478
                char *eol = strchr(logline, '\n');
1479

    
1480
                logline += 17;
1481

    
1482
                if (eol) {
1483
                    if (eol[-1] == '\r')
1484
                        eol--;
1485
                    http_log("%.*s\n", (int) (eol - logline), logline);
1486
                    c->suppress_log = 1;
1487
                }
1488
            }
1489

    
1490
#ifdef DEBUG_WMP
1491
            http_log("\nGot request:\n%s\n", c->buffer);
1492
#endif
1493

    
1494
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1495
                HTTPContext *wmpc;
1496

    
1497
                /* Now we have to find the client_id */
1498
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1499
                    if (wmpc->wmp_client_id == client_id)
1500
                        break;
1501
                }
1502

    
1503
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1504
                    wmpc->switch_pending = 1;
1505
            }
1506

    
1507
            snprintf(msg, sizeof(msg), "POST command not handled");
1508
            c->stream = 0;
1509
            goto send_error;
1510
        }
1511
        if (http_start_receive_data(c) < 0) {
1512
            snprintf(msg, sizeof(msg), "could not open feed");
1513
            goto send_error;
1514
        }
1515
        c->http_error = 0;
1516
        c->state = HTTPSTATE_RECEIVE_DATA;
1517
        return 0;
1518
    }
1519

    
1520
#ifdef DEBUG_WMP
1521
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1522
        http_log("\nGot request:\n%s\n", c->buffer);
1523
#endif
1524

    
1525
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1526
        goto send_stats;
1527

    
1528
    /* open input stream */
1529
    if (open_input_stream(c, info) < 0) {
1530
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1531
        goto send_error;
1532
    }
1533

    
1534
    /* prepare http header */
1535
    q = c->buffer;
1536
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1537
    mime_type = c->stream->fmt->mime_type;
1538
    if (!mime_type)
1539
        mime_type = "application/x-octet-stream";
1540
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1541

    
1542
    /* for asf, we need extra headers */
1543
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1544
        /* Need to allocate a client id */
1545

    
1546
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1547

    
1548
        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);
1549
    }
1550
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1551
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1552

    
1553
    /* prepare output buffer */
1554
    c->http_error = 0;
1555
    c->buffer_ptr = c->buffer;
1556
    c->buffer_end = q;
1557
    c->state = HTTPSTATE_SEND_HEADER;
1558
    return 0;
1559
 send_error:
1560
    c->http_error = 404;
1561
    q = c->buffer;
1562
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1563
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1564
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1565
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1566
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1567
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1568
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1569

    
1570
    /* prepare output buffer */
1571
    c->buffer_ptr = c->buffer;
1572
    c->buffer_end = q;
1573
    c->state = HTTPSTATE_SEND_HEADER;
1574
    return 0;
1575
 send_stats:
1576
    compute_stats(c);
1577
    c->http_error = 200; /* horrible : we use this value to avoid
1578
                            going to the send data state */
1579
    c->state = HTTPSTATE_SEND_HEADER;
1580
    return 0;
1581
}
1582

    
1583
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1584
{
1585
    static const char *suffix = " kMGTP";
1586
    const char *s;
1587

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

    
1590
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1591
}
1592

    
1593
static void compute_stats(HTTPContext *c)
1594
{
1595
    HTTPContext *c1;
1596
    FFStream *stream;
1597
    char *p;
1598
    time_t ti;
1599
    int i, len;
1600
    ByteIOContext *pb;
1601

    
1602
    if (url_open_dyn_buf(&pb) < 0) {
1603
        /* XXX: return an error ? */
1604
        c->buffer_ptr = c->buffer;
1605
        c->buffer_end = c->buffer;
1606
        return;
1607
    }
1608

    
1609
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1610
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1611
    url_fprintf(pb, "Pragma: no-cache\r\n");
1612
    url_fprintf(pb, "\r\n");
1613

    
1614
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1615
    if (c->stream->feed_filename)
1616
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1617
    url_fprintf(pb, "</HEAD>\n<BODY>");
1618
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1619
    /* format status */
1620
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1621
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1622
    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");
1623
    stream = first_stream;
1624
    while (stream != NULL) {
1625
        char sfilename[1024];
1626
        char *eosf;
1627

    
1628
        if (stream->feed != stream) {
1629
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1630
            eosf = sfilename + strlen(sfilename);
1631
            if (eosf - sfilename >= 4) {
1632
                if (strcmp(eosf - 4, ".asf") == 0)
1633
                    strcpy(eosf - 4, ".asx");
1634
                else if (strcmp(eosf - 3, ".rm") == 0)
1635
                    strcpy(eosf - 3, ".ram");
1636
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1637
                    /* generate a sample RTSP director if
1638
                       unicast. Generate an SDP redirector if
1639
                       multicast */
1640
                    eosf = strrchr(sfilename, '.');
1641
                    if (!eosf)
1642
                        eosf = sfilename + strlen(sfilename);
1643
                    if (stream->is_multicast)
1644
                        strcpy(eosf, ".sdp");
1645
                    else
1646
                        strcpy(eosf, ".rtsp");
1647
                }
1648
            }
1649

    
1650
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1651
                         sfilename, stream->filename);
1652
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1653
                        stream->conns_served);
1654
            fmt_bytecount(pb, stream->bytes_served);
1655
            switch(stream->stream_type) {
1656
            case STREAM_TYPE_LIVE:
1657
                {
1658
                    int audio_bit_rate = 0;
1659
                    int video_bit_rate = 0;
1660
                    const char *audio_codec_name = "";
1661
                    const char *video_codec_name = "";
1662
                    const char *audio_codec_name_extra = "";
1663
                    const char *video_codec_name_extra = "";
1664

    
1665
                    for(i=0;i<stream->nb_streams;i++) {
1666
                        AVStream *st = stream->streams[i];
1667
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1668
                        switch(st->codec->codec_type) {
1669
                        case CODEC_TYPE_AUDIO:
1670
                            audio_bit_rate += st->codec->bit_rate;
1671
                            if (codec) {
1672
                                if (*audio_codec_name)
1673
                                    audio_codec_name_extra = "...";
1674
                                audio_codec_name = codec->name;
1675
                            }
1676
                            break;
1677
                        case CODEC_TYPE_VIDEO:
1678
                            video_bit_rate += st->codec->bit_rate;
1679
                            if (codec) {
1680
                                if (*video_codec_name)
1681
                                    video_codec_name_extra = "...";
1682
                                video_codec_name = codec->name;
1683
                            }
1684
                            break;
1685
                        case CODEC_TYPE_DATA:
1686
                            video_bit_rate += st->codec->bit_rate;
1687
                            break;
1688
                        default:
1689
                            abort();
1690
                        }
1691
                    }
1692
                    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",
1693
                                 stream->fmt->name,
1694
                                 stream->bandwidth,
1695
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1696
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1697
                    if (stream->feed)
1698
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1699
                    else
1700
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1701
                    url_fprintf(pb, "\n");
1702
                }
1703
                break;
1704
            default:
1705
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1706
                break;
1707
            }
1708
        }
1709
        stream = stream->next;
1710
    }
1711
    url_fprintf(pb, "</TABLE>\n");
1712

    
1713
    stream = first_stream;
1714
    while (stream != NULL) {
1715
        if (stream->feed == stream) {
1716
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1717
            if (stream->pid) {
1718
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1719

    
1720
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1721
                {
1722
                    FILE *pid_stat;
1723
                    char ps_cmd[64];
1724

    
1725
                    /* This is somewhat linux specific I guess */
1726
                    snprintf(ps_cmd, sizeof(ps_cmd),
1727
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1728
                             stream->pid);
1729

    
1730
                    pid_stat = popen(ps_cmd, "r");
1731
                    if (pid_stat) {
1732
                        char cpuperc[10];
1733
                        char cpuused[64];
1734

    
1735
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1736
                                   cpuused) == 2) {
1737
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1738
                                         cpuperc, cpuused);
1739
                        }
1740
                        fclose(pid_stat);
1741
                    }
1742
                }
1743
#endif
1744

    
1745
                url_fprintf(pb, "<p>");
1746
            }
1747
            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");
1748

    
1749
            for (i = 0; i < stream->nb_streams; i++) {
1750
                AVStream *st = stream->streams[i];
1751
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1752
                const char *type = "unknown";
1753
                char parameters[64];
1754

    
1755
                parameters[0] = 0;
1756

    
1757
                switch(st->codec->codec_type) {
1758
                case CODEC_TYPE_AUDIO:
1759
                    type = "audio";
1760
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1761
                    break;
1762
                case CODEC_TYPE_VIDEO:
1763
                    type = "video";
1764
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1765
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1766
                    break;
1767
                default:
1768
                    abort();
1769
                }
1770
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1771
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1772
            }
1773
            url_fprintf(pb, "</table>\n");
1774

    
1775
        }
1776
        stream = stream->next;
1777
    }
1778

    
1779
#if 0
1780
    {
1781
        float avg;
1782
        AVCodecContext *enc;
1783
        char buf[1024];
1784

1785
        /* feed status */
1786
        stream = first_feed;
1787
        while (stream != NULL) {
1788
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1789
            url_fprintf(pb, "<TABLE>\n");
1790
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1791
            for(i=0;i<stream->nb_streams;i++) {
1792
                AVStream *st = stream->streams[i];
1793
                FeedData *fdata = st->priv_data;
1794
                enc = st->codec;
1795

1796
                avcodec_string(buf, sizeof(buf), enc);
1797
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1798
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1799
                    avg /= enc->frame_size;
1800
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1801
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1802
            }
1803
            url_fprintf(pb, "</TABLE>\n");
1804
            stream = stream->next_feed;
1805
        }
1806
    }
1807
#endif
1808

    
1809
    /* connection status */
1810
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1811

    
1812
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1813
                 nb_connections, nb_max_connections);
1814

    
1815
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1816
                 current_bandwidth, max_bandwidth);
1817

    
1818
    url_fprintf(pb, "<TABLE>\n");
1819
    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");
1820
    c1 = first_http_ctx;
1821
    i = 0;
1822
    while (c1 != NULL) {
1823
        int bitrate;
1824
        int j;
1825

    
1826
        bitrate = 0;
1827
        if (c1->stream) {
1828
            for (j = 0; j < c1->stream->nb_streams; j++) {
1829
                if (!c1->stream->feed)
1830
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1831
                else if (c1->feed_streams[j] >= 0)
1832
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1833
            }
1834
        }
1835

    
1836
        i++;
1837
        p = inet_ntoa(c1->from_addr.sin_addr);
1838
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1839
                    i,
1840
                    c1->stream ? c1->stream->filename : "",
1841
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1842
                    p,
1843
                    c1->protocol,
1844
                    http_state[c1->state]);
1845
        fmt_bytecount(pb, bitrate);
1846
        url_fprintf(pb, "<td align=right>");
1847
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1848
        url_fprintf(pb, "<td align=right>");
1849
        fmt_bytecount(pb, c1->data_count);
1850
        url_fprintf(pb, "\n");
1851
        c1 = c1->next;
1852
    }
1853
    url_fprintf(pb, "</TABLE>\n");
1854

    
1855
    /* date */
1856
    ti = time(NULL);
1857
    p = ctime(&ti);
1858
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1859
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1860

    
1861
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1862
    c->buffer_ptr = c->pb_buffer;
1863
    c->buffer_end = c->pb_buffer + len;
1864
}
1865

    
1866
/* check if the parser needs to be opened for stream i */
1867
static void open_parser(AVFormatContext *s, int i)
1868
{
1869
    AVStream *st = s->streams[i];
1870
    AVCodec *codec;
1871

    
1872
    if (!st->codec->codec) {
1873
        codec = avcodec_find_decoder(st->codec->codec_id);
1874
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1875
            st->codec->parse_only = 1;
1876
            if (avcodec_open(st->codec, codec) < 0)
1877
                st->codec->parse_only = 0;
1878
        }
1879
    }
1880
}
1881

    
1882
static int open_input_stream(HTTPContext *c, const char *info)
1883
{
1884
    char buf[128];
1885
    char input_filename[1024];
1886
    AVFormatContext *s;
1887
    int buf_size, i;
1888
    int64_t stream_pos;
1889

    
1890
    /* find file name */
1891
    if (c->stream->feed) {
1892
        strcpy(input_filename, c->stream->feed->feed_filename);
1893
        buf_size = FFM_PACKET_SIZE;
1894
        /* compute position (absolute time) */
1895
        if (find_info_tag(buf, sizeof(buf), "date", info))
1896
        {
1897
            stream_pos = parse_date(buf, 0);
1898
            if (stream_pos == INT64_MIN)
1899
                return -1;
1900
        }
1901
        else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1902
            int prebuffer = strtol(buf, 0, 10);
1903
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1904
        } else
1905
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1906
    } else {
1907
        strcpy(input_filename, c->stream->feed_filename);
1908
        buf_size = 0;
1909
        /* compute position (relative time) */
1910
        if (find_info_tag(buf, sizeof(buf), "date", info))
1911
        {
1912
            stream_pos = parse_date(buf, 1);
1913
            if (stream_pos == INT64_MIN)
1914
                return -1;
1915
        }
1916
        else
1917
            stream_pos = 0;
1918
    }
1919
    if (input_filename[0] == '\0')
1920
        return -1;
1921

    
1922
#if 0
1923
    { time_t when = stream_pos / 1000000;
1924
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1925
    }
1926
#endif
1927

    
1928
    /* open stream */
1929
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1930
                           buf_size, c->stream->ap_in) < 0) {
1931
        http_log("%s not found", input_filename);
1932
        return -1;
1933
    }
1934
    s->flags |= AVFMT_FLAG_GENPTS;
1935
    c->fmt_in = s;
1936
    av_find_stream_info(c->fmt_in);
1937

    
1938
    /* open each parser */
1939
    for(i=0;i<s->nb_streams;i++)
1940
        open_parser(s, i);
1941

    
1942
    /* choose stream as clock source (we favorize video stream if
1943
       present) for packet sending */
1944
    c->pts_stream_index = 0;
1945
    for(i=0;i<c->stream->nb_streams;i++) {
1946
        if (c->pts_stream_index == 0 &&
1947
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1948
            c->pts_stream_index = i;
1949
        }
1950
    }
1951

    
1952
#if 1
1953
    if (c->fmt_in->iformat->read_seek)
1954
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1955
#endif
1956
    /* set the start time (needed for maxtime and RTP packet timing) */
1957
    c->start_time = cur_time;
1958
    c->first_pts = AV_NOPTS_VALUE;
1959
    return 0;
1960
}
1961

    
1962
/* return the server clock (in us) */
1963
static int64_t get_server_clock(HTTPContext *c)
1964
{
1965
    /* compute current pts value from system time */
1966
    return (cur_time - c->start_time) * 1000;
1967
}
1968

    
1969
/* return the estimated time at which the current packet must be sent
1970
   (in us) */
1971
static int64_t get_packet_send_clock(HTTPContext *c)
1972
{
1973
    int bytes_left, bytes_sent, frame_bytes;
1974

    
1975
    frame_bytes = c->cur_frame_bytes;
1976
    if (frame_bytes <= 0)
1977
        return c->cur_pts;
1978
    else {
1979
        bytes_left = c->buffer_end - c->buffer_ptr;
1980
        bytes_sent = frame_bytes - bytes_left;
1981
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1982
    }
1983
}
1984

    
1985

    
1986
static int http_prepare_data(HTTPContext *c)
1987
{
1988
    int i, len, ret;
1989
    AVFormatContext *ctx;
1990

    
1991
    av_freep(&c->pb_buffer);
1992
    switch(c->state) {
1993
    case HTTPSTATE_SEND_DATA_HEADER:
1994
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1995
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
1996
                   sizeof(c->fmt_ctx.author));
1997
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
1998
                   sizeof(c->fmt_ctx.comment));
1999
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2000
                   sizeof(c->fmt_ctx.copyright));
2001
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2002
                   sizeof(c->fmt_ctx.title));
2003

    
2004
        /* open output stream by using specified codecs */
2005
        c->fmt_ctx.oformat = c->stream->fmt;
2006
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2007
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2008
            AVStream *st;
2009
            AVStream *src;
2010
            st = av_mallocz(sizeof(AVStream));
2011
            st->codec= avcodec_alloc_context();
2012
            c->fmt_ctx.streams[i] = st;
2013
            /* if file or feed, then just take streams from FFStream struct */
2014
            if (!c->stream->feed ||
2015
                c->stream->feed == c->stream)
2016
                src = c->stream->streams[i];
2017
            else
2018
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2019

    
2020
            *st = *src;
2021
            st->priv_data = 0;
2022
            st->codec->frame_number = 0; /* XXX: should be done in
2023
                                           AVStream, not in codec */
2024
            /* I'm pretty sure that this is not correct...
2025
             * However, without it, we crash
2026
             */
2027
            st->codec->coded_frame = &dummy_frame;
2028
        }
2029
        c->got_key_frame = 0;
2030

    
2031
        /* prepare header and save header data in a stream */
2032
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2033
            /* XXX: potential leak */
2034
            return -1;
2035
        }
2036
        c->fmt_ctx.pb->is_streamed = 1;
2037

    
2038
        av_set_parameters(&c->fmt_ctx, NULL);
2039
        if (av_write_header(&c->fmt_ctx) < 0)
2040
            return -1;
2041

    
2042
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2043
        c->buffer_ptr = c->pb_buffer;
2044
        c->buffer_end = c->pb_buffer + len;
2045

    
2046
        c->state = HTTPSTATE_SEND_DATA;
2047
        c->last_packet_sent = 0;
2048
        break;
2049
    case HTTPSTATE_SEND_DATA:
2050
        /* find a new packet */
2051
        {
2052
            AVPacket pkt;
2053

    
2054
            /* read a packet from the input stream */
2055
            if (c->stream->feed)
2056
                ffm_set_write_index(c->fmt_in,
2057
                                    c->stream->feed->feed_write_index,
2058
                                    c->stream->feed->feed_size);
2059

    
2060
            if (c->stream->max_time &&
2061
                c->stream->max_time + c->start_time - cur_time < 0)
2062
                /* We have timed out */
2063
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
2064
            else {
2065
            redo:
2066
                if (av_read_frame(c->fmt_in, &pkt) < 0) {
2067
                    if (c->stream->feed && c->stream->feed->feed_opened) {
2068
                        /* if coming from feed, it means we reached the end of the
2069
                           ffm file, so must wait for more data */
2070
                        c->state = HTTPSTATE_WAIT_FEED;
2071
                        return 1; /* state changed */
2072
                    } else {
2073
                        if (c->stream->loop) {
2074
                            av_close_input_file(c->fmt_in);
2075
                            c->fmt_in = NULL;
2076
                            if (open_input_stream(c, "") < 0)
2077
                                goto no_loop;
2078
                            goto redo;
2079
                        } else {
2080
                        no_loop:
2081
                            /* must send trailer now because eof or error */
2082
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2083
                        }
2084
                    }
2085
                } else {
2086
                    /* update first pts if needed */
2087
                    if (c->first_pts == AV_NOPTS_VALUE) {
2088
                        c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2089
                        c->start_time = cur_time;
2090
                    }
2091
                    /* send it to the appropriate stream */
2092
                    if (c->stream->feed) {
2093
                        /* if coming from a feed, select the right stream */
2094
                        if (c->switch_pending) {
2095
                            c->switch_pending = 0;
2096
                            for(i=0;i<c->stream->nb_streams;i++) {
2097
                                if (c->switch_feed_streams[i] == pkt.stream_index)
2098
                                    if (pkt.flags & PKT_FLAG_KEY)
2099
                                        do_switch_stream(c, i);
2100
                                if (c->switch_feed_streams[i] >= 0)
2101
                                    c->switch_pending = 1;
2102
                            }
2103
                        }
2104
                        for(i=0;i<c->stream->nb_streams;i++) {
2105
                            if (c->feed_streams[i] == pkt.stream_index) {
2106
                                pkt.stream_index = i;
2107
                                if (pkt.flags & PKT_FLAG_KEY)
2108
                                    c->got_key_frame |= 1 << i;
2109
                                /* See if we have all the key frames, then
2110
                                 * we start to send. This logic is not quite
2111
                                 * right, but it works for the case of a
2112
                                 * single video stream with one or more
2113
                                 * audio streams (for which every frame is
2114
                                 * typically a key frame).
2115
                                 */
2116
                                if (!c->stream->send_on_key ||
2117
                                    ((c->got_key_frame + 1) >> c->stream->nb_streams))
2118
                                    goto send_it;
2119
                            }
2120
                        }
2121
                    } else {
2122
                        AVCodecContext *codec;
2123

    
2124
                    send_it:
2125
                        /* specific handling for RTP: we use several
2126
                           output stream (one for each RTP
2127
                           connection). XXX: need more abstract handling */
2128
                        if (c->is_packetized) {
2129
                            AVStream *st;
2130
                            /* compute send time and duration */
2131
                            st = c->fmt_in->streams[pkt.stream_index];
2132
                            c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2133
                            if (st->start_time != AV_NOPTS_VALUE)
2134
                                c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2135
                            c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2136
#if 0
2137
                            printf("index=%d pts=%0.3f duration=%0.6f\n",
2138
                                   pkt.stream_index,
2139
                                   (double)c->cur_pts /
2140
                                   AV_TIME_BASE,
2141
                                   (double)c->cur_frame_duration /
2142
                                   AV_TIME_BASE);
2143
#endif
2144
                            /* find RTP context */
2145
                            c->packet_stream_index = pkt.stream_index;
2146
                            ctx = c->rtp_ctx[c->packet_stream_index];
2147
                            if(!ctx) {
2148
                              av_free_packet(&pkt);
2149
                              break;
2150
                            }
2151
                            codec = ctx->streams[0]->codec;
2152
                            /* only one stream per RTP connection */
2153
                            pkt.stream_index = 0;
2154
                        } else {
2155
                            ctx = &c->fmt_ctx;
2156
                            /* Fudge here */
2157
                            codec = ctx->streams[pkt.stream_index]->codec;
2158
                        }
2159

    
2160
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2161
                        if (c->is_packetized) {
2162
                            int max_packet_size;
2163
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2164
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2165
                            else
2166
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2167
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2168
                        } else {
2169
                            ret = url_open_dyn_buf(&ctx->pb);
2170
                        }
2171
                        if (ret < 0) {
2172
                            /* XXX: potential leak */
2173
                            return -1;
2174
                        }
2175
                        if (pkt.dts != AV_NOPTS_VALUE)
2176
                            pkt.dts = av_rescale_q(pkt.dts,
2177
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2178
                                ctx->streams[pkt.stream_index]->time_base);
2179
                        if (pkt.pts != AV_NOPTS_VALUE)
2180
                            pkt.pts = av_rescale_q(pkt.pts,
2181
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2182
                                ctx->streams[pkt.stream_index]->time_base);
2183
                        if (av_write_frame(ctx, &pkt))
2184
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2185

    
2186
                        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2187
                        c->cur_frame_bytes = len;
2188
                        c->buffer_ptr = c->pb_buffer;
2189
                        c->buffer_end = c->pb_buffer + len;
2190

    
2191
                        codec->frame_number++;
2192
                        if (len == 0)
2193
                            goto redo;
2194
                    }
2195
                    av_free_packet(&pkt);
2196
                }
2197
            }
2198
        }
2199
        break;
2200
    default:
2201
    case HTTPSTATE_SEND_DATA_TRAILER:
2202
        /* last packet test ? */
2203
        if (c->last_packet_sent || c->is_packetized)
2204
            return -1;
2205
        ctx = &c->fmt_ctx;
2206
        /* prepare header */
2207
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2208
            /* XXX: potential leak */
2209
            return -1;
2210
        }
2211
        av_write_trailer(ctx);
2212
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2213
        c->buffer_ptr = c->pb_buffer;
2214
        c->buffer_end = c->pb_buffer + len;
2215

    
2216
        c->last_packet_sent = 1;
2217
        break;
2218
    }
2219
    return 0;
2220
}
2221

    
2222
/* should convert the format at the same time */
2223
/* send data starting at c->buffer_ptr to the output connection
2224
   (either UDP or TCP connection) */
2225
static int http_send_data(HTTPContext *c)
2226
{
2227
    int len, ret;
2228

    
2229
    for(;;) {
2230
        if (c->buffer_ptr >= c->buffer_end) {
2231
            ret = http_prepare_data(c);
2232
            if (ret < 0)
2233
                return -1;
2234
            else if (ret != 0)
2235
                /* state change requested */
2236
                break;
2237
        } else {
2238
            if (c->is_packetized) {
2239
                /* RTP data output */
2240
                len = c->buffer_end - c->buffer_ptr;
2241
                if (len < 4) {
2242
                    /* fail safe - should never happen */
2243
                fail1:
2244
                    c->buffer_ptr = c->buffer_end;
2245
                    return 0;
2246
                }
2247
                len = (c->buffer_ptr[0] << 24) |
2248
                    (c->buffer_ptr[1] << 16) |
2249
                    (c->buffer_ptr[2] << 8) |
2250
                    (c->buffer_ptr[3]);
2251
                if (len > (c->buffer_end - c->buffer_ptr))
2252
                    goto fail1;
2253
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2254
                    /* nothing to send yet: we can wait */
2255
                    return 0;
2256
                }
2257

    
2258
                c->data_count += len;
2259
                update_datarate(&c->datarate, c->data_count);
2260
                if (c->stream)
2261
                    c->stream->bytes_served += len;
2262

    
2263
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2264
                    /* RTP packets are sent inside the RTSP TCP connection */
2265
                    ByteIOContext *pb;
2266
                    int interleaved_index, size;
2267
                    uint8_t header[4];
2268
                    HTTPContext *rtsp_c;
2269

    
2270
                    rtsp_c = c->rtsp_c;
2271
                    /* if no RTSP connection left, error */
2272
                    if (!rtsp_c)
2273
                        return -1;
2274
                    /* if already sending something, then wait. */
2275
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2276
                        break;
2277
                    if (url_open_dyn_buf(&pb) < 0)
2278
                        goto fail1;
2279
                    interleaved_index = c->packet_stream_index * 2;
2280
                    /* RTCP packets are sent at odd indexes */
2281
                    if (c->buffer_ptr[1] == 200)
2282
                        interleaved_index++;
2283
                    /* write RTSP TCP header */
2284
                    header[0] = '$';
2285
                    header[1] = interleaved_index;
2286
                    header[2] = len >> 8;
2287
                    header[3] = len;
2288
                    put_buffer(pb, header, 4);
2289
                    /* write RTP packet data */
2290
                    c->buffer_ptr += 4;
2291
                    put_buffer(pb, c->buffer_ptr, len);
2292
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2293
                    /* prepare asynchronous TCP sending */
2294
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2295
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2296
                    c->buffer_ptr += len;
2297

    
2298
                    /* send everything we can NOW */
2299
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2300
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2301
                    if (len > 0)
2302
                        rtsp_c->packet_buffer_ptr += len;
2303
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2304
                        /* if we could not send all the data, we will
2305
                           send it later, so a new state is needed to
2306
                           "lock" the RTSP TCP connection */
2307
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2308
                        break;
2309
                    } else
2310
                        /* all data has been sent */
2311
                        av_freep(&c->packet_buffer);
2312
                } else {
2313
                    /* send RTP packet directly in UDP */
2314
                    c->buffer_ptr += 4;
2315
                    url_write(c->rtp_handles[c->packet_stream_index],
2316
                              c->buffer_ptr, len);
2317
                    c->buffer_ptr += len;
2318
                    /* here we continue as we can send several packets per 10 ms slot */
2319
                }
2320
            } else {
2321
                /* TCP data output */
2322
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2323
                if (len < 0) {
2324
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2325
                        ff_neterrno() != FF_NETERROR(EINTR))
2326
                        /* error : close connection */
2327
                        return -1;
2328
                    else
2329
                        return 0;
2330
                } else
2331
                    c->buffer_ptr += len;
2332

    
2333
                c->data_count += len;
2334
                update_datarate(&c->datarate, c->data_count);
2335
                if (c->stream)
2336
                    c->stream->bytes_served += len;
2337
                break;
2338
            }
2339
        }
2340
    } /* for(;;) */
2341
    return 0;
2342
}
2343

    
2344
static int http_start_receive_data(HTTPContext *c)
2345
{
2346
    int fd;
2347

    
2348
    if (c->stream->feed_opened)
2349
        return -1;
2350

    
2351
    /* Don't permit writing to this one */
2352
    if (c->stream->readonly)
2353
        return -1;
2354

    
2355
    /* open feed */
2356
    fd = open(c->stream->feed_filename, O_RDWR);
2357
    if (fd < 0)
2358
        return -1;
2359
    c->feed_fd = fd;
2360

    
2361
    c->stream->feed_write_index = ffm_read_write_index(fd);
2362
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2363
    lseek(fd, 0, SEEK_SET);
2364

    
2365
    /* init buffer input */
2366
    c->buffer_ptr = c->buffer;
2367
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2368
    c->stream->feed_opened = 1;
2369
    return 0;
2370
}
2371

    
2372
static int http_receive_data(HTTPContext *c)
2373
{
2374
    HTTPContext *c1;
2375

    
2376
    if (c->buffer_end > c->buffer_ptr) {
2377
        int len;
2378

    
2379
        len = recv(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
                goto fail;
2385
        } else if (len == 0)
2386
            /* end of connection : close it */
2387
            goto fail;
2388
        else {
2389
            c->buffer_ptr += len;
2390
            c->data_count += len;
2391
            update_datarate(&c->datarate, c->data_count);
2392
        }
2393
    }
2394

    
2395
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2396
        if (c->buffer[0] != 'f' ||
2397
            c->buffer[1] != 'm') {
2398
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2399
            goto fail;
2400
        }
2401
    }
2402

    
2403
    if (c->buffer_ptr >= c->buffer_end) {
2404
        FFStream *feed = c->stream;
2405
        /* a packet has been received : write it in the store, except
2406
           if header */
2407
        if (c->data_count > FFM_PACKET_SIZE) {
2408

    
2409
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2410
            /* XXX: use llseek or url_seek */
2411
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2412
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2413

    
2414
            feed->feed_write_index += FFM_PACKET_SIZE;
2415
            /* update file size */
2416
            if (feed->feed_write_index > c->stream->feed_size)
2417
                feed->feed_size = feed->feed_write_index;
2418

    
2419
            /* handle wrap around if max file size reached */
2420
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2421
                feed->feed_write_index = FFM_PACKET_SIZE;
2422

    
2423
            /* write index */
2424
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2425

    
2426
            /* wake up any waiting connections */
2427
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2428
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2429
                    c1->stream->feed == c->stream->feed)
2430
                    c1->state = HTTPSTATE_SEND_DATA;
2431
            }
2432
        } else {
2433
            /* We have a header in our hands that contains useful data */
2434
            AVFormatContext s;
2435
            AVInputFormat *fmt_in;
2436
            int i;
2437

    
2438
            memset(&s, 0, sizeof(s));
2439

    
2440
            url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2441
            s.pb->is_streamed = 1;
2442

    
2443
            /* use feed output format name to find corresponding input format */
2444
            fmt_in = av_find_input_format(feed->fmt->name);
2445
            if (!fmt_in)
2446
                goto fail;
2447

    
2448
            if (fmt_in->priv_data_size > 0) {
2449
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2450
                if (!s.priv_data)
2451
                    goto fail;
2452
            } else
2453
                s.priv_data = NULL;
2454

    
2455
            if (fmt_in->read_header(&s, 0) < 0) {
2456
                av_freep(&s.priv_data);
2457
                goto fail;
2458
            }
2459

    
2460
            /* Now we have the actual streams */
2461
            if (s.nb_streams != feed->nb_streams) {
2462
                av_freep(&s.priv_data);
2463
                goto fail;
2464
            }
2465
            for (i = 0; i < s.nb_streams; i++)
2466
                memcpy(feed->streams[i]->codec,
2467
                       s.streams[i]->codec, sizeof(AVCodecContext));
2468
            av_freep(&s.priv_data);
2469
        }
2470
        c->buffer_ptr = c->buffer;
2471
    }
2472

    
2473
    return 0;
2474
 fail:
2475
    c->stream->feed_opened = 0;
2476
    close(c->feed_fd);
2477
    return -1;
2478
}
2479

    
2480
/********************************************************************/
2481
/* RTSP handling */
2482

    
2483
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2484
{
2485
    const char *str;
2486
    time_t ti;
2487
    char *p;
2488
    char buf2[32];
2489

    
2490
    switch(error_number) {
2491
    case RTSP_STATUS_OK:
2492
        str = "OK";
2493
        break;
2494
    case RTSP_STATUS_METHOD:
2495
        str = "Method Not Allowed";
2496
        break;
2497
    case RTSP_STATUS_BANDWIDTH:
2498
        str = "Not Enough Bandwidth";
2499
        break;
2500
    case RTSP_STATUS_SESSION:
2501
        str = "Session Not Found";
2502
        break;
2503
    case RTSP_STATUS_STATE:
2504
        str = "Method Not Valid in This State";
2505
        break;
2506
    case RTSP_STATUS_AGGREGATE:
2507
        str = "Aggregate operation not allowed";
2508
        break;
2509
    case RTSP_STATUS_ONLY_AGGREGATE:
2510
        str = "Only aggregate operation allowed";
2511
        break;
2512
    case RTSP_STATUS_TRANSPORT:
2513
        str = "Unsupported transport";
2514
        break;
2515
    case RTSP_STATUS_INTERNAL:
2516
        str = "Internal Server Error";
2517
        break;
2518
    case RTSP_STATUS_SERVICE:
2519
        str = "Service Unavailable";
2520
        break;
2521
    case RTSP_STATUS_VERSION:
2522
        str = "RTSP Version not supported";
2523
        break;
2524
    default:
2525
        str = "Unknown Error";
2526
        break;
2527
    }
2528

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

    
2532
    /* output GMT time */
2533
    ti = time(NULL);
2534
    p = ctime(&ti);
2535
    strcpy(buf2, p);
2536
    p = buf2 + strlen(p) - 1;
2537
    if (*p == '\n')
2538
        *p = '\0';
2539
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2540
}
2541

    
2542
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2543
{
2544
    rtsp_reply_header(c, error_number);
2545
    url_fprintf(c->pb, "\r\n");
2546
}
2547

    
2548
static int rtsp_parse_request(HTTPContext *c)
2549
{
2550
    const char *p, *p1, *p2;
2551
    char cmd[32];
2552
    char url[1024];
2553
    char protocol[32];
2554
    char line[1024];
2555
    int len;
2556
    RTSPHeader header1, *header = &header1;
2557

    
2558
    c->buffer_ptr[0] = '\0';
2559
    p = c->buffer;
2560

    
2561
    get_word(cmd, sizeof(cmd), &p);
2562
    get_word(url, sizeof(url), &p);
2563
    get_word(protocol, sizeof(protocol), &p);
2564

    
2565
    av_strlcpy(c->method, cmd, sizeof(c->method));
2566
    av_strlcpy(c->url, url, sizeof(c->url));
2567
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2568

    
2569
    if (url_open_dyn_buf(&c->pb) < 0) {
2570
        /* XXX: cannot do more */
2571
        c->pb = NULL; /* safety */
2572
        return -1;
2573
    }
2574

    
2575
    /* check version name */
2576
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2577
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2578
        goto the_end;
2579
    }
2580

    
2581
    /* parse each header line */
2582
    memset(header, 0, sizeof(RTSPHeader));
2583
    /* skip to next line */
2584
    while (*p != '\n' && *p != '\0')
2585
        p++;
2586
    if (*p == '\n')
2587
        p++;
2588
    while (*p != '\0') {
2589
        p1 = strchr(p, '\n');
2590
        if (!p1)
2591
            break;
2592
        p2 = p1;
2593
        if (p2 > p && p2[-1] == '\r')
2594
            p2--;
2595
        /* skip empty line */
2596
        if (p2 == p)
2597
            break;
2598
        len = p2 - p;
2599
        if (len > sizeof(line) - 1)
2600
            len = sizeof(line) - 1;
2601
        memcpy(line, p, len);
2602
        line[len] = '\0';
2603
        rtsp_parse_line(header, line);
2604
        p = p1 + 1;
2605
    }
2606

    
2607
    /* handle sequence number */
2608
    c->seq = header->seq;
2609

    
2610
    if (!strcmp(cmd, "DESCRIBE"))
2611
        rtsp_cmd_describe(c, url);
2612
    else if (!strcmp(cmd, "OPTIONS"))
2613
        rtsp_cmd_options(c, url);
2614
    else if (!strcmp(cmd, "SETUP"))
2615
        rtsp_cmd_setup(c, url, header);
2616
    else if (!strcmp(cmd, "PLAY"))
2617
        rtsp_cmd_play(c, url, header);
2618
    else if (!strcmp(cmd, "PAUSE"))
2619
        rtsp_cmd_pause(c, url, header);
2620
    else if (!strcmp(cmd, "TEARDOWN"))
2621
        rtsp_cmd_teardown(c, url, header);
2622
    else
2623
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2624

    
2625
 the_end:
2626
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2627
    c->pb = NULL; /* safety */
2628
    if (len < 0) {
2629
        /* XXX: cannot do more */
2630
        return -1;
2631
    }
2632
    c->buffer_ptr = c->pb_buffer;
2633
    c->buffer_end = c->pb_buffer + len;
2634
    c->state = RTSPSTATE_SEND_REPLY;
2635
    return 0;
2636
}
2637

    
2638
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2639
                                   struct in_addr my_ip)
2640
{
2641
    AVFormatContext *avc;
2642
    AVStream avs[MAX_STREAMS];
2643
    int i;
2644

    
2645
    avc =  av_alloc_format_context();
2646
    if (avc == NULL) {
2647
        return -1;
2648
    }
2649
    if (stream->title[0] != 0) {
2650
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2651
    } else {
2652
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2653
    }
2654
    avc->nb_streams = stream->nb_streams;
2655
    if (stream->is_multicast) {
2656
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2657
                 inet_ntoa(stream->multicast_ip),
2658
                 stream->multicast_port, stream->multicast_ttl);
2659
    }
2660

    
2661
    for(i = 0; i < stream->nb_streams; i++) {
2662
        avc->streams[i] = &avs[i];
2663
        avc->streams[i]->codec = stream->streams[i]->codec;
2664
    }
2665
    *pbuffer = av_mallocz(2048);
2666
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2667
    av_free(avc);
2668

    
2669
    return strlen(*pbuffer);
2670
}
2671

    
2672
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2673
{
2674
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2675
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2676
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2677
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2678
    url_fprintf(c->pb, "\r\n");
2679
}
2680

    
2681
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2682
{
2683
    FFStream *stream;
2684
    char path1[1024];
2685
    const char *path;
2686
    uint8_t *content;
2687
    int content_length, len;
2688
    struct sockaddr_in my_addr;
2689

    
2690
    /* find which url is asked */
2691
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2692
    path = path1;
2693
    if (*path == '/')
2694
        path++;
2695

    
2696
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2697
        if (!stream->is_feed &&
2698
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2699
            !strcmp(path, stream->filename)) {
2700
            goto found;
2701
        }
2702
    }
2703
    /* no stream found */
2704
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2705
    return;
2706

    
2707
 found:
2708
    /* prepare the media description in sdp format */
2709

    
2710
    /* get the host IP */
2711
    len = sizeof(my_addr);
2712
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2713
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2714
    if (content_length < 0) {
2715
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2716
        return;
2717
    }
2718
    rtsp_reply_header(c, RTSP_STATUS_OK);
2719
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2720
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2721
    url_fprintf(c->pb, "\r\n");
2722
    put_buffer(c->pb, content, content_length);
2723
}
2724

    
2725
static HTTPContext *find_rtp_session(const char *session_id)
2726
{
2727
    HTTPContext *c;
2728

    
2729
    if (session_id[0] == '\0')
2730
        return NULL;
2731

    
2732
    for(c = first_http_ctx; c != NULL; c = c->next) {
2733
        if (!strcmp(c->session_id, session_id))
2734
            return c;
2735
    }
2736
    return NULL;
2737
}
2738

    
2739
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2740
{
2741
    RTSPTransportField *th;
2742
    int i;
2743

    
2744
    for(i=0;i<h->nb_transports;i++) {
2745
        th = &h->transports[i];
2746
        if (th->protocol == protocol)
2747
            return th;
2748
    }
2749
    return NULL;
2750
}
2751

    
2752
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2753
                           RTSPHeader *h)
2754
{
2755
    FFStream *stream;
2756
    int stream_index, port;
2757
    char buf[1024];
2758
    char path1[1024];
2759
    const char *path;
2760
    HTTPContext *rtp_c;
2761
    RTSPTransportField *th;
2762
    struct sockaddr_in dest_addr;
2763
    RTSPActionServerSetup setup;
2764

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

    
2771
    /* now check each stream */
2772
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2773
        if (!stream->is_feed &&
2774
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2775
            /* accept aggregate filenames only if single stream */
2776
            if (!strcmp(path, stream->filename)) {
2777
                if (stream->nb_streams != 1) {
2778
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2779
                    return;
2780
                }
2781
                stream_index = 0;
2782
                goto found;
2783
            }
2784

    
2785
            for(stream_index = 0; stream_index < stream->nb_streams;
2786
                stream_index++) {
2787
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2788
                         stream->filename, stream_index);
2789
                if (!strcmp(path, buf))
2790
                    goto found;
2791
            }
2792
        }
2793
    }
2794
    /* no stream found */
2795
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2796
    return;
2797
 found:
2798

    
2799
    /* generate session id if needed */
2800
    if (h->session_id[0] == '\0')
2801
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2802
                 av_random(&random_state), av_random(&random_state));
2803

    
2804
    /* find rtp session, and create it if none found */
2805
    rtp_c = find_rtp_session(h->session_id);
2806
    if (!rtp_c) {
2807
        /* always prefer UDP */
2808
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2809
        if (!th) {
2810
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2811
            if (!th) {
2812
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2813
                return;
2814
            }
2815
        }
2816

    
2817
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2818
                                   th->protocol);
2819
        if (!rtp_c) {
2820
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2821
            return;
2822
        }
2823

    
2824
        /* open input stream */
2825
        if (open_input_stream(rtp_c, "") < 0) {
2826
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2827
            return;
2828
        }
2829
    }
2830

    
2831
    /* test if stream is OK (test needed because several SETUP needs
2832
       to be done for a given file) */
2833
    if (rtp_c->stream != stream) {
2834
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2835
        return;
2836
    }
2837

    
2838
    /* test if stream is already set up */
2839
    if (rtp_c->rtp_ctx[stream_index]) {
2840
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2841
        return;
2842
    }
2843

    
2844
    /* check transport */
2845
    th = find_transport(h, rtp_c->rtp_protocol);
2846
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2847
                th->client_port_min <= 0)) {
2848
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2849
        return;
2850
    }
2851

    
2852
    /* setup default options */
2853
    setup.transport_option[0] = '\0';
2854
    dest_addr = rtp_c->from_addr;
2855
    dest_addr.sin_port = htons(th->client_port_min);
2856

    
2857
    /* setup stream */
2858
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2859
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2860
        return;
2861
    }
2862

    
2863
    /* now everything is OK, so we can send the connection parameters */
2864
    rtsp_reply_header(c, RTSP_STATUS_OK);
2865
    /* session ID */
2866
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2867

    
2868
    switch(rtp_c->rtp_protocol) {
2869
    case RTSP_PROTOCOL_RTP_UDP:
2870
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2871
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2872
                    "client_port=%d-%d;server_port=%d-%d",
2873
                    th->client_port_min, th->client_port_min + 1,
2874
                    port, port + 1);
2875
        break;
2876
    case RTSP_PROTOCOL_RTP_TCP:
2877
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2878
                    stream_index * 2, stream_index * 2 + 1);
2879
        break;
2880
    default:
2881
        break;
2882
    }
2883
    if (setup.transport_option[0] != '\0')
2884
        url_fprintf(c->pb, ";%s", setup.transport_option);
2885
    url_fprintf(c->pb, "\r\n");
2886

    
2887

    
2888
    url_fprintf(c->pb, "\r\n");
2889
}
2890

    
2891

    
2892
/* find an rtp connection by using the session ID. Check consistency
2893
   with filename */
2894
static HTTPContext *find_rtp_session_with_url(const char *url,
2895
                                              const char *session_id)
2896
{
2897
    HTTPContext *rtp_c;
2898
    char path1[1024];
2899
    const char *path;
2900
    char buf[1024];
2901
    int s;
2902

    
2903
    rtp_c = find_rtp_session(session_id);
2904
    if (!rtp_c)
2905
        return NULL;
2906

    
2907
    /* find which url is asked */
2908
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2909
    path = path1;
2910
    if (*path == '/')
2911
        path++;
2912
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2913
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2914
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2915
        rtp_c->stream->filename, s);
2916
      if(!strncmp(path, buf, sizeof(buf))) {
2917
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2918
        return rtp_c;
2919
      }
2920
    }
2921
    return NULL;
2922
}
2923

    
2924
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2925
{
2926
    HTTPContext *rtp_c;
2927

    
2928
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2929
    if (!rtp_c) {
2930
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2931
        return;
2932
    }
2933

    
2934
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2935
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2936
        rtp_c->state != HTTPSTATE_READY) {
2937
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2938
        return;
2939
    }
2940

    
2941
#if 0
2942
    /* XXX: seek in stream */
2943
    if (h->range_start != AV_NOPTS_VALUE) {
2944
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2945
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2946
    }
2947
#endif
2948

    
2949
    rtp_c->state = HTTPSTATE_SEND_DATA;
2950

    
2951
    /* now everything is OK, so we can send the connection parameters */
2952
    rtsp_reply_header(c, RTSP_STATUS_OK);
2953
    /* session ID */
2954
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2955
    url_fprintf(c->pb, "\r\n");
2956
}
2957

    
2958
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2959
{
2960
    HTTPContext *rtp_c;
2961

    
2962
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2963
    if (!rtp_c) {
2964
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2965
        return;
2966
    }
2967

    
2968
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2969
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2970
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2971
        return;
2972
    }
2973

    
2974
    rtp_c->state = HTTPSTATE_READY;
2975
    rtp_c->first_pts = AV_NOPTS_VALUE;
2976
    /* now everything is OK, so we can send the connection parameters */
2977
    rtsp_reply_header(c, RTSP_STATUS_OK);
2978
    /* session ID */
2979
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2980
    url_fprintf(c->pb, "\r\n");
2981
}
2982

    
2983
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2984
{
2985
    HTTPContext *rtp_c;
2986
    char session_id[32];
2987

    
2988
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2989
    if (!rtp_c) {
2990
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2991
        return;
2992
    }
2993

    
2994
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2995

    
2996
    /* abort the session */
2997
    close_connection(rtp_c);
2998

    
2999
    /* now everything is OK, so we can send the connection parameters */
3000
    rtsp_reply_header(c, RTSP_STATUS_OK);
3001
    /* session ID */
3002
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3003
    url_fprintf(c->pb, "\r\n");
3004
}
3005

    
3006

    
3007
/********************************************************************/
3008
/* RTP handling */
3009

    
3010
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3011
                                       FFStream *stream, const char *session_id,
3012
                                       enum RTSPProtocol rtp_protocol)
3013
{
3014
    HTTPContext *c = NULL;
3015
    const char *proto_str;
3016

    
3017
    /* XXX: should output a warning page when coming
3018
       close to the connection limit */
3019
    if (nb_connections >= nb_max_connections)
3020
        goto fail;
3021

    
3022
    /* add a new connection */
3023
    c = av_mallocz(sizeof(HTTPContext));
3024
    if (!c)
3025
        goto fail;
3026

    
3027
    c->fd = -1;
3028
    c->poll_entry = NULL;
3029
    c->from_addr = *from_addr;
3030
    c->buffer_size = IOBUFFER_INIT_SIZE;
3031
    c->buffer = av_malloc(c->buffer_size);
3032
    if (!c->buffer)
3033
        goto fail;
3034
    nb_connections++;
3035
    c->stream = stream;
3036
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3037
    c->state = HTTPSTATE_READY;
3038
    c->is_packetized = 1;
3039
    c->rtp_protocol = rtp_protocol;
3040

    
3041
    /* protocol is shown in statistics */
3042
    switch(c->rtp_protocol) {
3043
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3044
        proto_str = "MCAST";
3045
        break;
3046
    case RTSP_PROTOCOL_RTP_UDP:
3047
        proto_str = "UDP";
3048
        break;
3049
    case RTSP_PROTOCOL_RTP_TCP:
3050
        proto_str = "TCP";
3051
        break;
3052
    default:
3053
        proto_str = "???";
3054
        break;
3055
    }
3056
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3057
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3058

    
3059
    current_bandwidth += stream->bandwidth;
3060

    
3061
    c->next = first_http_ctx;
3062
    first_http_ctx = c;
3063
    return c;
3064

    
3065
 fail:
3066
    if (c) {
3067
        av_free(c->buffer);
3068
        av_free(c);
3069
    }
3070
    return NULL;
3071
}
3072

    
3073
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3074
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3075
   used. */
3076
static int rtp_new_av_stream(HTTPContext *c,
3077
                             int stream_index, struct sockaddr_in *dest_addr,
3078
                             HTTPContext *rtsp_c)
3079
{
3080
    AVFormatContext *ctx;
3081
    AVStream *st;
3082
    char *ipaddr;
3083
    URLContext *h;
3084
    uint8_t *dummy_buf;
3085
    char buf2[32];
3086
    int max_packet_size;
3087

    
3088
    /* now we can open the relevant output stream */
3089
    ctx = av_alloc_format_context();
3090
    if (!ctx)
3091
        return -1;
3092
    ctx->oformat = guess_format("rtp", NULL, NULL);
3093

    
3094
    st = av_mallocz(sizeof(AVStream));
3095
    if (!st)
3096
        goto fail;
3097
    st->codec= avcodec_alloc_context();
3098
    ctx->nb_streams = 1;
3099
    ctx->streams[0] = st;
3100

    
3101
    if (!c->stream->feed ||
3102
        c->stream->feed == c->stream)
3103
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3104
    else
3105
        memcpy(st,
3106
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3107
               sizeof(AVStream));
3108
    st->priv_data = NULL;
3109

    
3110
    /* build destination RTP address */
3111
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3112

    
3113
    switch(c->rtp_protocol) {
3114
    case RTSP_PROTOCOL_RTP_UDP:
3115
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3116
        /* RTP/UDP case */
3117

    
3118
        /* XXX: also pass as parameter to function ? */
3119
        if (c->stream->is_multicast) {
3120
            int ttl;
3121
            ttl = c->stream->multicast_ttl;
3122
            if (!ttl)
3123
                ttl = 16;
3124
            snprintf(ctx->filename, sizeof(ctx->filename),
3125
                     "rtp://%s:%d?multicast=1&ttl=%d",
3126
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3127
        } else {
3128
            snprintf(ctx->filename, sizeof(ctx->filename),
3129
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3130
        }
3131

    
3132
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3133
            goto fail;
3134
        c->rtp_handles[stream_index] = h;
3135
        max_packet_size = url_get_max_packet_size(h);
3136
        break;
3137
    case RTSP_PROTOCOL_RTP_TCP:
3138
        /* RTP/TCP case */
3139
        c->rtsp_c = rtsp_c;
3140
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3141
        break;
3142
    default:
3143
        goto fail;
3144
    }
3145

    
3146
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3147
             ipaddr, ntohs(dest_addr->sin_port),
3148
             ctime1(buf2),
3149
             c->stream->filename, stream_index, c->protocol);
3150

    
3151
    /* normally, no packets should be output here, but the packet size may be checked */
3152
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3153
        /* XXX: close stream */
3154
        goto fail;
3155
    }
3156
    av_set_parameters(ctx, NULL);
3157
    if (av_write_header(ctx) < 0) {
3158
    fail:
3159
        if (h)
3160
            url_close(h);
3161
        av_free(ctx);
3162
        return -1;
3163
    }
3164
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3165
    av_free(dummy_buf);
3166

    
3167
    c->rtp_ctx[stream_index] = ctx;
3168
    return 0;
3169
}
3170

    
3171
/********************************************************************/
3172
/* ffserver initialization */
3173

    
3174
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3175
{
3176
    AVStream *fst;
3177

    
3178
    fst = av_mallocz(sizeof(AVStream));
3179
    if (!fst)
3180
        return NULL;
3181
    fst->codec= avcodec_alloc_context();
3182
    fst->priv_data = av_mallocz(sizeof(FeedData));
3183
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3184
    fst->codec->coded_frame = &dummy_frame;
3185
    fst->index = stream->nb_streams;
3186
    av_set_pts_info(fst, 33, 1, 90000);
3187
    stream->streams[stream->nb_streams++] = fst;
3188
    return fst;
3189
}
3190

    
3191
/* return the stream number in the feed */
3192
static int add_av_stream(FFStream *feed, AVStream *st)
3193
{
3194
    AVStream *fst;
3195
    AVCodecContext *av, *av1;
3196
    int i;
3197

    
3198
    av = st->codec;
3199
    for(i=0;i<feed->nb_streams;i++) {
3200
        st = feed->streams[i];
3201
        av1 = st->codec;
3202
        if (av1->codec_id == av->codec_id &&
3203
            av1->codec_type == av->codec_type &&
3204
            av1->bit_rate == av->bit_rate) {
3205

    
3206
            switch(av->codec_type) {
3207
            case CODEC_TYPE_AUDIO:
3208
                if (av1->channels == av->channels &&
3209
                    av1->sample_rate == av->sample_rate)
3210
                    goto found;
3211
                break;
3212
            case CODEC_TYPE_VIDEO:
3213
                if (av1->width == av->width &&
3214
                    av1->height == av->height &&
3215
                    av1->time_base.den == av->time_base.den &&
3216
                    av1->time_base.num == av->time_base.num &&
3217
                    av1->gop_size == av->gop_size)
3218
                    goto found;
3219
                break;
3220
            default:
3221
                abort();
3222
            }
3223
        }
3224
    }
3225

    
3226
    fst = add_av_stream1(feed, av);
3227
    if (!fst)
3228
        return -1;
3229
    return feed->nb_streams - 1;
3230
 found:
3231
    return i;
3232
}
3233

    
3234
static void remove_stream(FFStream *stream)
3235
{
3236
    FFStream **ps;
3237
    ps = &first_stream;
3238
    while (*ps != NULL) {
3239
        if (*ps == stream)
3240
            *ps = (*ps)->next;
3241
        else
3242
            ps = &(*ps)->next;
3243
    }
3244
}
3245

    
3246
/* specific mpeg4 handling : we extract the raw parameters */
3247
static void extract_mpeg4_header(AVFormatContext *infile)
3248
{
3249
    int mpeg4_count, i, size;
3250
    AVPacket pkt;
3251
    AVStream *st;
3252
    const uint8_t *p;
3253

    
3254
    mpeg4_count = 0;
3255
    for(i=0;i<infile->nb_streams;i++) {
3256
        st = infile->streams[i];
3257
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3258
            st->codec->extradata_size == 0) {
3259
            mpeg4_count++;
3260
        }
3261
    }
3262
    if (!mpeg4_count)
3263
        return;
3264

    
3265
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3266
    while (mpeg4_count > 0) {
3267
        if (av_read_packet(infile, &pkt) < 0)
3268
            break;
3269
        st = infile->streams[pkt.stream_index];
3270
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3271
            st->codec->extradata_size == 0) {
3272
            av_freep(&st->codec->extradata);
3273
            /* fill extradata with the header */
3274
            /* XXX: we make hard suppositions here ! */
3275
            p = pkt.data;
3276
            while (p < pkt.data + pkt.size - 4) {
3277
                /* stop when vop header is found */
3278
                if (p[0] == 0x00 && p[1] == 0x00 &&
3279
                    p[2] == 0x01 && p[3] == 0xb6) {
3280
                    size = p - pkt.data;
3281
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3282
                    st->codec->extradata = av_malloc(size);
3283
                    st->codec->extradata_size = size;
3284
                    memcpy(st->codec->extradata, pkt.data, size);
3285
                    break;
3286
                }
3287
                p++;
3288
            }
3289
            mpeg4_count--;
3290
        }
3291
        av_free_packet(&pkt);
3292
    }
3293
}
3294

    
3295
/* compute the needed AVStream for each file */
3296
static void build_file_streams(void)
3297
{
3298
    FFStream *stream, *stream_next;
3299
    AVFormatContext *infile;
3300
    int i;
3301

    
3302
    /* gather all streams */
3303
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3304
        stream_next = stream->next;
3305
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3306
            !stream->feed) {
3307
            /* the stream comes from a file */
3308
            /* try to open the file */
3309
            /* open stream */
3310
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3311
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3312
                /* specific case : if transport stream output to RTP,
3313
                   we use a raw transport stream reader */
3314
                stream->ap_in->mpeg2ts_raw = 1;
3315
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3316
            }
3317

    
3318
            if (av_open_input_file(&infile, stream->feed_filename,
3319
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3320
                http_log("%s not found", stream->feed_filename);
3321
                /* remove stream (no need to spend more time on it) */
3322
            fail:
3323
                remove_stream(stream);
3324
            } else {
3325
                /* find all the AVStreams inside and reference them in
3326
                   'stream' */
3327
                if (av_find_stream_info(infile) < 0) {
3328
                    http_log("Could not find codec parameters from '%s'",
3329
                             stream->feed_filename);
3330
                    av_close_input_file(infile);
3331
                    goto fail;
3332
                }
3333
                extract_mpeg4_header(infile);
3334

    
3335
                for(i=0;i<infile->nb_streams;i++)
3336
                    add_av_stream1(stream, infile->streams[i]->codec);
3337

    
3338
                av_close_input_file(infile);
3339
            }
3340
        }
3341
    }
3342
}
3343

    
3344
/* compute the needed AVStream for each feed */
3345
static void build_feed_streams(void)
3346
{
3347
    FFStream *stream, *feed;
3348
    int i;
3349

    
3350
    /* gather all streams */
3351
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3352
        feed = stream->feed;
3353
        if (feed) {
3354
            if (!stream->is_feed) {
3355
                /* we handle a stream coming from a feed */
3356
                for(i=0;i<stream->nb_streams;i++)
3357
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3358
            }
3359
        }
3360
    }
3361

    
3362
    /* gather all streams */
3363
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3364
        feed = stream->feed;
3365
        if (feed) {
3366
            if (stream->is_feed) {
3367
                for(i=0;i<stream->nb_streams;i++)
3368
                    stream->feed_streams[i] = i;
3369
            }
3370
        }
3371
    }
3372

    
3373
    /* create feed files if needed */
3374
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3375
        int fd;
3376

    
3377
        if (url_exist(feed->feed_filename)) {
3378
            /* See if it matches */
3379
            AVFormatContext *s;
3380
            int matches = 0;
3381

    
3382
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3383
                /* Now see if it matches */
3384
                if (s->nb_streams == feed->nb_streams) {
3385
                    matches = 1;
3386
                    for(i=0;i<s->nb_streams;i++) {
3387
                        AVStream *sf, *ss;
3388
                        sf = feed->streams[i];
3389
                        ss = s->streams[i];
3390

    
3391
                        if (sf->index != ss->index ||
3392
                            sf->id != ss->id) {
3393
                            printf("Index & Id do not match for stream %d (%s)\n",
3394
                                   i, feed->feed_filename);
3395
                            matches = 0;
3396
                        } else {
3397
                            AVCodecContext *ccf, *ccs;
3398

    
3399
                            ccf = sf->codec;
3400
                            ccs = ss->codec;
3401
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3402

    
3403
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3404
                                printf("Codecs do not match for stream %d\n", i);
3405
                                matches = 0;
3406
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3407
                                printf("Codec bitrates do not match for stream %d\n", i);
3408
                                matches = 0;
3409
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3410
                                if (CHECK_CODEC(time_base.den) ||
3411
                                    CHECK_CODEC(time_base.num) ||
3412
                                    CHECK_CODEC(width) ||
3413
                                    CHECK_CODEC(height)) {
3414
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3415
                                    matches = 0;
3416
                                }
3417
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3418
                                if (CHECK_CODEC(sample_rate) ||
3419
                                    CHECK_CODEC(channels) ||
3420
                                    CHECK_CODEC(frame_size)) {
3421
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3422
                                    matches = 0;
3423
                                }
3424
                            } else {
3425
                                printf("Unknown codec type\n");
3426
                                matches = 0;
3427
                            }
3428
                        }
3429
                        if (!matches)
3430
                            break;
3431
                    }
3432
                } else
3433
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3434
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3435

    
3436
                av_close_input_file(s);
3437
            } else
3438
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3439
                        feed->feed_filename);
3440

    
3441
            if (!matches) {
3442
                if (feed->readonly) {
3443
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3444
                        feed->feed_filename);
3445
                    exit(1);
3446
                }
3447
                unlink(feed->feed_filename);
3448
            }
3449
        }
3450
        if (!url_exist(feed->feed_filename)) {
3451
            AVFormatContext s1, *s = &s1;
3452

    
3453
            if (feed->readonly) {
3454
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3455
                    feed->feed_filename);
3456
                exit(1);
3457
            }
3458

    
3459
            /* only write the header of the ffm file */
3460
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3461
                fprintf(stderr, "Could not open output feed file '%s'\n",
3462
                        feed->feed_filename);
3463
                exit(1);
3464
            }
3465
            s->oformat = feed->fmt;
3466
            s->nb_streams = feed->nb_streams;
3467
            for(i=0;i<s->nb_streams;i++) {
3468
                AVStream *st;
3469
                st = feed->streams[i];
3470
                s->streams[i] = st;
3471
            }
3472
            av_set_parameters(s, NULL);
3473
            if (av_write_header(s) < 0) {
3474
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3475
                exit(1);
3476
            }
3477
            /* XXX: need better api */
3478
            av_freep(&s->priv_data);
3479
            url_fclose(s->pb);
3480
        }
3481
        /* get feed size and write index */
3482
        fd = open(feed->feed_filename, O_RDONLY);
3483
        if (fd < 0) {
3484
            fprintf(stderr, "Could not open output feed file '%s'\n",
3485
                    feed->feed_filename);
3486
            exit(1);
3487
        }
3488

    
3489
        feed->feed_write_index = ffm_read_write_index(fd);
3490
        feed->feed_size = lseek(fd, 0, SEEK_END);
3491
        /* ensure that we do not wrap before the end of file */
3492
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3493
            feed->feed_max_size = feed->feed_size;
3494

    
3495
        close(fd);
3496
    }
3497
}
3498

    
3499
/* compute the bandwidth used by each stream */
3500
static void compute_bandwidth(void)
3501
{
3502
    int bandwidth, i;
3503
    FFStream *stream;
3504

    
3505
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3506
        bandwidth = 0;
3507
        for(i=0;i<stream->nb_streams;i++) {
3508
            AVStream *st = stream->streams[i];
3509
            switch(st->codec->codec_type) {
3510
            case CODEC_TYPE_AUDIO:
3511
            case CODEC_TYPE_VIDEO:
3512
                bandwidth += st->codec->bit_rate;
3513
                break;
3514
            default:
3515
                break;
3516
            }
3517
        }
3518
        stream->bandwidth = (bandwidth + 999) / 1000;
3519
    }
3520
}
3521

    
3522
static void get_arg(char *buf, int buf_size, const char **pp)
3523
{
3524
    const char *p;
3525
    char *q;
3526
    int quote;
3527

    
3528
    p = *pp;
3529
    while (isspace(*p)) p++;
3530
    q = buf;
3531
    quote = 0;
3532
    if (*p == '\"' || *p == '\'')
3533
        quote = *p++;
3534
    for(;;) {
3535
        if (quote) {
3536
            if (*p == quote)
3537
                break;
3538
        } else {
3539
            if (isspace(*p))
3540
                break;
3541
        }
3542
        if (*p == '\0')
3543
            break;
3544
        if ((q - buf) < buf_size - 1)
3545
            *q++ = *p;
3546
        p++;
3547
    }
3548
    *q = '\0';
3549
    if (quote && *p == quote)
3550
        p++;
3551
    *pp = p;
3552
}
3553

    
3554
/* add a codec and set the default parameters */
3555
static void add_codec(FFStream *stream, AVCodecContext *av)
3556
{
3557
    AVStream *st;
3558

    
3559
    /* compute default parameters */
3560
    switch(av->codec_type) {
3561
    case CODEC_TYPE_AUDIO:
3562
        if (av->bit_rate == 0)
3563
            av->bit_rate = 64000;
3564
        if (av->sample_rate == 0)
3565
            av->sample_rate = 22050;
3566
        if (av->channels == 0)
3567
            av->channels = 1;
3568
        break;
3569
    case CODEC_TYPE_VIDEO:
3570
        if (av->bit_rate == 0)
3571
            av->bit_rate = 64000;
3572
        if (av->time_base.num == 0){
3573
            av->time_base.den = 5;
3574
            av->time_base.num = 1;
3575
        }
3576
        if (av->width == 0 || av->height == 0) {
3577
            av->width = 160;
3578
            av->height = 128;
3579
        }
3580
        /* Bitrate tolerance is less for streaming */
3581
        if (av->bit_rate_tolerance == 0)
3582
            av->bit_rate_tolerance = av->bit_rate / 4;
3583
        if (av->qmin == 0)
3584
            av->qmin = 3;
3585
        if (av->qmax == 0)
3586
            av->qmax = 31;
3587
        if (av->max_qdiff == 0)
3588
            av->max_qdiff = 3;
3589
        av->qcompress = 0.5;
3590
        av->qblur = 0.5;
3591

    
3592
        if (!av->nsse_weight)
3593
            av->nsse_weight = 8;
3594

    
3595
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3596
        av->me_method = ME_EPZS;
3597
        av->rc_buffer_aggressivity = 1.0;
3598

    
3599
        if (!av->rc_eq)
3600
            av->rc_eq = "tex^qComp";
3601
        if (!av->i_quant_factor)
3602
            av->i_quant_factor = -0.8;
3603
        if (!av->b_quant_factor)
3604
            av->b_quant_factor = 1.25;
3605
        if (!av->b_quant_offset)
3606
            av->b_quant_offset = 1.25;
3607
        if (!av->rc_max_rate)
3608
            av->rc_max_rate = av->bit_rate * 2;
3609

    
3610
        if (av->rc_max_rate && !av->rc_buffer_size) {
3611
            av->rc_buffer_size = av->rc_max_rate;
3612
        }
3613

    
3614

    
3615
        break;
3616
    default:
3617
        abort();
3618
    }
3619

    
3620
    st = av_mallocz(sizeof(AVStream));
3621
    if (!st)
3622
        return;
3623
    st->codec = avcodec_alloc_context();
3624
    stream->streams[stream->nb_streams++] = st;
3625
    memcpy(st->codec, av, sizeof(AVCodecContext));
3626
}
3627

    
3628
static int opt_audio_codec(const char *arg)
3629
{
3630
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3631

    
3632
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3633
        return CODEC_ID_NONE;
3634

    
3635
    return p->id;
3636
}
3637

    
3638
static int opt_video_codec(const char *arg)
3639
{
3640
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3641

    
3642
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3643
        return CODEC_ID_NONE;
3644

    
3645
    return p->id;
3646
}
3647

    
3648
/* simplistic plugin support */
3649

    
3650
#ifdef HAVE_DLOPEN
3651
static void load_module(const char *filename)
3652
{
3653
    void *dll;
3654
    void (*init_func)(void);
3655
    dll = dlopen(filename, RTLD_NOW);
3656
    if (!dll) {
3657
        fprintf(stderr, "Could not load module '%s' - %s\n",
3658
                filename, dlerror());
3659
        return;
3660
    }
3661

    
3662
    init_func = dlsym(dll, "ffserver_module_init");
3663
    if (!init_func) {
3664
        fprintf(stderr,
3665
                "%s: init function 'ffserver_module_init()' not found\n",
3666
                filename);
3667
        dlclose(dll);
3668
    }
3669

    
3670
    init_func();
3671
}
3672
#endif
3673

    
3674
static int parse_ffconfig(const char *filename)
3675
{
3676
    FILE *f;
3677
    char line[1024];
3678
    char cmd[64];
3679
    char arg[1024];
3680
    const char *p;
3681
    int val, errors, line_num;
3682
    FFStream **last_stream, *stream, *redirect;
3683
    FFStream **last_feed, *feed;
3684
    AVCodecContext audio_enc, video_enc;
3685
    int audio_id, video_id;
3686

    
3687
    f = fopen(filename, "r");
3688
    if (!f) {
3689
        perror(filename);
3690
        return -1;
3691
    }
3692

    
3693
    errors = 0;
3694
    line_num = 0;
3695
    first_stream = NULL;
3696
    last_stream = &first_stream;
3697
    first_feed = NULL;
3698
    last_feed = &first_feed;
3699
    stream = NULL;
3700
    feed = NULL;
3701
    redirect = NULL;
3702
    audio_id = CODEC_ID_NONE;
3703
    video_id = CODEC_ID_NONE;
3704
    for(;;) {
3705
        if (fgets(line, sizeof(line), f) == NULL)
3706
            break;
3707
        line_num++;
3708
        p = line;
3709
        while (isspace(*p))
3710
            p++;
3711
        if (*p == '\0' || *p == '#')
3712
            continue;
3713

    
3714
        get_arg(cmd, sizeof(cmd), &p);
3715

    
3716
        if (!strcasecmp(cmd, "Port")) {
3717
            get_arg(arg, sizeof(arg), &p);
3718
            val = atoi(arg);
3719
            if (val < 1 || val > 65536) {
3720
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3721
                        filename, line_num, arg);
3722
                errors++;
3723
            }
3724
            my_http_addr.sin_port = htons(val);
3725
        } else if (!strcasecmp(cmd, "BindAddress")) {
3726
            get_arg(arg, sizeof(arg), &p);
3727
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3728
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3729
                        filename, line_num, arg);
3730
                errors++;
3731
            }
3732
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3733
            ffserver_daemon = 0;
3734
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3735
            get_arg(arg, sizeof(arg), &p);
3736
            val = atoi(arg);
3737
            if (val < 1 || val > 65536) {
3738
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3739
                        filename, line_num, arg);
3740
                errors++;
3741
            }
3742
            my_rtsp_addr.sin_port = htons(atoi(arg));
3743
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3744
            get_arg(arg, sizeof(arg), &p);
3745
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3746
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3747
                        filename, line_num, arg);
3748
                errors++;
3749
            }
3750
        } else if (!strcasecmp(cmd, "MaxClients")) {
3751
            get_arg(arg, sizeof(arg), &p);
3752
            val = atoi(arg);
3753
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3754
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3755
                        filename, line_num, arg);
3756
                errors++;
3757
            } else {
3758
                nb_max_connections = val;
3759
            }
3760
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3761
            get_arg(arg, sizeof(arg), &p);
3762
            val = atoi(arg);
3763
            if (val < 10 || val > 100000) {
3764
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3765
                        filename, line_num, arg);
3766
                errors++;
3767
            } else
3768
                max_bandwidth = val;
3769
        } else if (!strcasecmp(cmd, "CustomLog")) {
3770
            get_arg(logfilename, sizeof(logfilename), &p);
3771
        } else if (!strcasecmp(cmd, "<Feed")) {
3772
            /*********************************************/
3773
            /* Feed related options */
3774
            char *q;
3775
            if (stream || feed) {
3776
                fprintf(stderr, "%s:%d: Already in a tag\n",
3777
                        filename, line_num);
3778
            } else {
3779
                feed = av_mallocz(sizeof(FFStream));
3780
                /* add in stream list */
3781
                *last_stream = feed;
3782
                last_stream = &feed->next;
3783
                /* add in feed list */
3784
                *last_feed = feed;
3785
                last_feed = &feed->next_feed;
3786

    
3787
                get_arg(feed->filename, sizeof(feed->filename), &p);
3788
                q = strrchr(feed->filename, '>');
3789
                if (*q)
3790
                    *q = '\0';
3791
                feed->fmt = guess_format("ffm", NULL, NULL);
3792
                /* defaut feed file */
3793
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3794
                         "/tmp/%s.ffm", feed->filename);
3795
                feed->feed_max_size = 5 * 1024 * 1024;
3796
                feed->is_feed = 1;
3797
                feed->feed = feed; /* self feeding :-) */
3798
            }
3799
        } else if (!strcasecmp(cmd, "Launch")) {
3800
            if (feed) {
3801
                int i;
3802

    
3803
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3804

    
3805
                for (i = 0; i < 62; i++) {
3806
                    get_arg(arg, sizeof(arg), &p);
3807
                    if (!arg[0])
3808
                        break;
3809

    
3810
                    feed->child_argv[i] = av_strdup(arg);
3811
                }
3812

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

    
3815
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3816
                    "http://%s:%d/%s",
3817
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3818
                    inet_ntoa(my_http_addr.sin_addr),
3819
                    ntohs(my_http_addr.sin_port), feed->filename);
3820

    
3821
                if (ffserver_debug)
3822
                {
3823
                    int j;
3824
                    fprintf(stdout, "Launch commandline: ");
3825
                    for (j = 0; j <= i; j++)
3826
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3827
                    fprintf(stdout, "\n");
3828
                }
3829
            }
3830
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3831
            if (feed) {
3832
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3833
                feed->readonly = 1;
3834
            } else if (stream) {
3835
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3836
            }
3837
        } else if (!strcasecmp(cmd, "File")) {
3838
            if (feed) {
3839
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3840
            } else if (stream)
3841
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3842
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3843
            if (feed) {
3844
                char *p1;
3845
                double fsize;
3846

    
3847
                get_arg(arg, sizeof(arg), &p);
3848
                p1 = arg;
3849
                fsize = strtod(p1, &p1);
3850
                switch(toupper(*p1)) {
3851
                case 'K':
3852
                    fsize *= 1024;
3853
                    break;
3854
                case 'M':
3855
                    fsize *= 1024 * 1024;
3856
                    break;
3857
                case 'G':
3858
                    fsize *= 1024 * 1024 * 1024;
3859
                    break;
3860
                }
3861
                feed->feed_max_size = (int64_t)fsize;
3862
            }
3863
        } else if (!strcasecmp(cmd, "</Feed>")) {
3864
            if (!feed) {
3865
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3866
                        filename, line_num);
3867
                errors++;
3868
            }
3869
            feed = NULL;
3870
        } else if (!strcasecmp(cmd, "<Stream")) {
3871
            /*********************************************/
3872
            /* Stream related options */
3873
            char *q;
3874
            if (stream || feed) {
3875
                fprintf(stderr, "%s:%d: Already in a tag\n",
3876
                        filename, line_num);
3877
            } else {
3878
                stream = av_mallocz(sizeof(FFStream));
3879
                *last_stream = stream;
3880
                last_stream = &stream->next;
3881

    
3882
                get_arg(stream->filename, sizeof(stream->filename), &p);
3883
                q = strrchr(stream->filename, '>');
3884
                if (*q)
3885
                    *q = '\0';
3886
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3887
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3888
                memset(&video_enc, 0, sizeof(AVCodecContext));
3889
                audio_id = CODEC_ID_NONE;
3890
                video_id = CODEC_ID_NONE;
3891
                if (stream->fmt) {
3892
                    audio_id = stream->fmt->audio_codec;
3893
                    video_id = stream->fmt->video_codec;
3894
                }
3895
            }
3896
        } else if (!strcasecmp(cmd, "Feed")) {
3897
            get_arg(arg, sizeof(arg), &p);
3898
            if (stream) {
3899
                FFStream *sfeed;
3900

    
3901
                sfeed = first_feed;
3902
                while (sfeed != NULL) {
3903
                    if (!strcmp(sfeed->filename, arg))
3904
                        break;
3905
                    sfeed = sfeed->next_feed;
3906
                }
3907
                if (!sfeed)
3908
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3909
                            filename, line_num, arg);
3910
                else
3911
                    stream->feed = sfeed;
3912
            }
3913
        } else if (!strcasecmp(cmd, "Format")) {
3914
            get_arg(arg, sizeof(arg), &p);
3915
            if (!strcmp(arg, "status")) {
3916
                stream->stream_type = STREAM_TYPE_STATUS;
3917
                stream->fmt = NULL;
3918
            } else {
3919
                stream->stream_type = STREAM_TYPE_LIVE;
3920
                /* jpeg cannot be used here, so use single frame jpeg */
3921
                if (!strcmp(arg, "jpeg"))
3922
                    strcpy(arg, "mjpeg");
3923
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3924
                if (!stream->fmt) {
3925
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
3926
                            filename, line_num, arg);
3927
                    errors++;
3928
                }
3929
            }
3930
            if (stream->fmt) {
3931
                audio_id = stream->fmt->audio_codec;
3932
                video_id = stream->fmt->video_codec;
3933
            }
3934
        } else if (!strcasecmp(cmd, "InputFormat")) {
3935
            get_arg(arg, sizeof(arg), &p);
3936
            stream->ifmt = av_find_input_format(arg);
3937
            if (!stream->ifmt) {
3938
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
3939
                        filename, line_num, arg);
3940
            }
3941
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3942
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3943
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3944
            } else {
3945
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
3946
                            filename, line_num);
3947
                errors++;
3948
            }
3949
        } else if (!strcasecmp(cmd, "Author")) {
3950
            if (stream)
3951
                get_arg(stream->author, sizeof(stream->author), &p);
3952
        } else if (!strcasecmp(cmd, "Comment")) {
3953
            if (stream)
3954
                get_arg(stream->comment, sizeof(stream->comment), &p);
3955
        } else if (!strcasecmp(cmd, "Copyright")) {
3956
            if (stream)
3957
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
3958
        } else if (!strcasecmp(cmd, "Title")) {
3959
            if (stream)
3960
                get_arg(stream->title, sizeof(stream->title), &p);
3961
        } else if (!strcasecmp(cmd, "Preroll")) {
3962
            get_arg(arg, sizeof(arg), &p);
3963
            if (stream)
3964
                stream->prebuffer = atof(arg) * 1000;
3965
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3966
            if (stream)
3967
                stream->send_on_key = 1;
3968
        } else if (!strcasecmp(cmd, "AudioCodec")) {
3969
            get_arg(arg, sizeof(arg), &p);
3970
            audio_id = opt_audio_codec(arg);
3971
            if (audio_id == CODEC_ID_NONE) {
3972
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
3973
                        filename, line_num, arg);
3974
                errors++;
3975
            }
3976
        } else if (!strcasecmp(cmd, "VideoCodec")) {
3977
            get_arg(arg, sizeof(arg), &p);
3978
            video_id = opt_video_codec(arg);
3979
            if (video_id == CODEC_ID_NONE) {
3980
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
3981
                        filename, line_num, arg);
3982
                errors++;
3983
            }
3984
        } else if (!strcasecmp(cmd, "MaxTime")) {
3985
            get_arg(arg, sizeof(arg), &p);
3986
            if (stream)
3987
                stream->max_time = atof(arg) * 1000;
3988
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
3989
            get_arg(arg, sizeof(arg), &p);
3990
            if (stream)
3991
                audio_enc.bit_rate = atoi(arg) * 1000;
3992
        } else if (!strcasecmp(cmd, "AudioChannels")) {
3993
            get_arg(arg, sizeof(arg), &p);
3994
            if (stream)
3995
                audio_enc.channels = atoi(arg);
3996
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
3997
            get_arg(arg, sizeof(arg), &p);
3998
            if (stream)
3999
                audio_enc.sample_rate = atoi(arg);
4000
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4001
            get_arg(arg, sizeof(arg), &p);
4002
            if (stream) {
4003
//                audio_enc.quality = atof(arg) * 1000;
4004
            }
4005
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4006
            if (stream) {
4007
                int minrate, maxrate;
4008

    
4009
                get_arg(arg, sizeof(arg), &p);
4010

    
4011
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4012
                    video_enc.rc_min_rate = minrate * 1000;
4013
                    video_enc.rc_max_rate = maxrate * 1000;
4014
                } else {
4015
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4016
                            filename, line_num, arg);
4017
                    errors++;
4018
                }
4019
            }
4020
        } else if (!strcasecmp(cmd, "Debug")) {
4021
            if (stream) {
4022
                get_arg(arg, sizeof(arg), &p);
4023
                video_enc.debug = strtol(arg,0,0);
4024
            }
4025
        } else if (!strcasecmp(cmd, "Strict")) {
4026
            if (stream) {
4027
                get_arg(arg, sizeof(arg), &p);
4028
                video_enc.strict_std_compliance = atoi(arg);
4029
            }
4030
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4031
            if (stream) {
4032
                get_arg(arg, sizeof(arg), &p);
4033
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4034
            }
4035
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4036
            if (stream) {
4037
                get_arg(arg, sizeof(arg), &p);
4038
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4039
            }
4040
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4041
            get_arg(arg, sizeof(arg), &p);
4042
            if (stream) {
4043
                video_enc.bit_rate = atoi(arg) * 1000;
4044
            }
4045
        } else if (!strcasecmp(cmd, "VideoSize")) {
4046
            get_arg(arg, sizeof(arg), &p);
4047
            if (stream) {
4048
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4049
                if ((video_enc.width % 16) != 0 ||
4050
                    (video_enc.height % 16) != 0) {
4051
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4052
                            filename, line_num);
4053
                    errors++;
4054
                }
4055
            }
4056
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4057
            get_arg(arg, sizeof(arg), &p);
4058
            if (stream) {
4059
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4060
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4061
            }
4062
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4063
            get_arg(arg, sizeof(arg), &p);
4064
            if (stream)
4065
                video_enc.gop_size = atoi(arg);
4066
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4067
            if (stream)
4068
                video_enc.gop_size = 1;
4069
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4070
            if (stream)
4071
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4072
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4073
            if (stream) {
4074
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4075
                video_enc.flags |= CODEC_FLAG_4MV;
4076
            }
4077
        } else if (!strcasecmp(cmd, "VideoTag")) {
4078
            get_arg(arg, sizeof(arg), &p);
4079
            if ((strlen(arg) == 4) && stream)
4080
                video_enc.codec_tag = ff_get_fourcc(arg);
4081
        } else if (!strcasecmp(cmd, "BitExact")) {
4082
            if (stream)
4083
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4084
        } else if (!strcasecmp(cmd, "DctFastint")) {
4085
            if (stream)
4086
                video_enc.dct_algo  = FF_DCT_FASTINT;
4087
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4088
            if (stream)
4089
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4090
        } else if (!strcasecmp(cmd, "Qscale")) {
4091
            get_arg(arg, sizeof(arg), &p);
4092
            if (stream) {
4093
                video_enc.flags |= CODEC_FLAG_QSCALE;
4094
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4095
            }
4096
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4097
            get_arg(arg, sizeof(arg), &p);
4098
            if (stream) {
4099
                video_enc.max_qdiff = atoi(arg);
4100
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4101
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4102
                            filename, line_num);
4103
                    errors++;
4104
                }
4105
            }
4106
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4107
            get_arg(arg, sizeof(arg), &p);
4108
            if (stream) {
4109
                video_enc.qmax = atoi(arg);
4110
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4111
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4112
                            filename, line_num);
4113
                    errors++;
4114
                }
4115
            }
4116
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4117
            get_arg(arg, sizeof(arg), &p);
4118
            if (stream) {
4119
                video_enc.qmin = atoi(arg);
4120
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4121
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4122
                            filename, line_num);
4123
                    errors++;
4124
                }
4125
            }
4126
        } else if (!strcasecmp(cmd, "LumaElim")) {
4127
            get_arg(arg, sizeof(arg), &p);
4128
            if (stream)
4129
                video_enc.luma_elim_threshold = atoi(arg);
4130
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4131
            get_arg(arg, sizeof(arg), &p);
4132
            if (stream)
4133
                video_enc.chroma_elim_threshold = atoi(arg);
4134
        } else if (!strcasecmp(cmd, "LumiMask")) {
4135
            get_arg(arg, sizeof(arg), &p);
4136
            if (stream)
4137
                video_enc.lumi_masking = atof(arg);
4138
        } else if (!strcasecmp(cmd, "DarkMask")) {
4139
            get_arg(arg, sizeof(arg), &p);
4140
            if (stream)
4141
                video_enc.dark_masking = atof(arg);
4142
        } else if (!strcasecmp(cmd, "NoVideo")) {
4143
            video_id = CODEC_ID_NONE;
4144
        } else if (!strcasecmp(cmd, "NoAudio")) {
4145
            audio_id = CODEC_ID_NONE;
4146
        } else if (!strcasecmp(cmd, "ACL")) {
4147
            IPAddressACL acl;
4148

    
4149
            get_arg(arg, sizeof(arg), &p);
4150
            if (strcasecmp(arg, "allow") == 0)
4151
                acl.action = IP_ALLOW;
4152
            else if (strcasecmp(arg, "deny") == 0)
4153
                acl.action = IP_DENY;
4154
            else {
4155
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4156
                        filename, line_num, arg);
4157
                errors++;
4158
            }
4159

    
4160
            get_arg(arg, sizeof(arg), &p);
4161

    
4162
            if (resolve_host(&acl.first, arg) != 0) {
4163
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4164
                        filename, line_num, arg);
4165
                errors++;
4166
            } else
4167
                acl.last = acl.first;
4168

    
4169
            get_arg(arg, sizeof(arg), &p);
4170

    
4171
            if (arg[0]) {
4172
                if (resolve_host(&acl.last, arg) != 0) {
4173
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4174
                            filename, line_num, arg);
4175
                    errors++;
4176
                }
4177
            }
4178

    
4179
            if (!errors) {
4180
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4181
                IPAddressACL **naclp = 0;
4182

    
4183
                acl.next = 0;
4184
                *nacl = acl;
4185

    
4186
                if (stream)
4187
                    naclp = &stream->acl;
4188
                else if (feed)
4189
                    naclp = &feed->acl;
4190
                else {
4191
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4192
                            filename, line_num);
4193
                    errors++;
4194
                }
4195

    
4196
                if (naclp) {
4197
                    while (*naclp)
4198
                        naclp = &(*naclp)->next;
4199

    
4200
                    *naclp = nacl;
4201
                }
4202
            }
4203
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4204
            get_arg(arg, sizeof(arg), &p);
4205
            if (stream) {
4206
                av_freep(&stream->rtsp_option);
4207
                stream->rtsp_option = av_strdup(arg);
4208
            }
4209
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4210
            get_arg(arg, sizeof(arg), &p);
4211
            if (stream) {
4212
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4213
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4214
                            filename, line_num, arg);
4215
                    errors++;
4216
                }
4217
                stream->is_multicast = 1;
4218
                stream->loop = 1; /* default is looping */
4219
            }
4220
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4221
            get_arg(arg, sizeof(arg), &p);
4222
            if (stream)
4223
                stream->multicast_port = atoi(arg);
4224
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4225
            get_arg(arg, sizeof(arg), &p);
4226
            if (stream)
4227
                stream->multicast_ttl = atoi(arg);
4228
        } else if (!strcasecmp(cmd, "NoLoop")) {
4229
            if (stream)
4230
                stream->loop = 0;
4231
        } else if (!strcasecmp(cmd, "</Stream>")) {
4232
            if (!stream) {
4233
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4234
                        filename, line_num);
4235
                errors++;
4236
            }
4237
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4238
                if (audio_id != CODEC_ID_NONE) {
4239
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4240
                    audio_enc.codec_id = audio_id;
4241
                    add_codec(stream, &audio_enc);
4242
                }
4243
                if (video_id != CODEC_ID_NONE) {
4244
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4245
                    video_enc.codec_id = video_id;
4246
                    add_codec(stream, &video_enc);
4247
                }
4248
            }
4249
            stream = NULL;
4250
        } else if (!strcasecmp(cmd, "<Redirect")) {
4251
            /*********************************************/
4252
            char *q;
4253
            if (stream || feed || redirect) {
4254
                fprintf(stderr, "%s:%d: Already in a tag\n",
4255
                        filename, line_num);
4256
                errors++;
4257
            } else {
4258
                redirect = av_mallocz(sizeof(FFStream));
4259
                *last_stream = redirect;
4260
                last_stream = &redirect->next;
4261

    
4262
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4263
                q = strrchr(redirect->filename, '>');
4264
                if (*q)
4265
                    *q = '\0';
4266
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4267
            }
4268
        } else if (!strcasecmp(cmd, "URL")) {
4269
            if (redirect)
4270
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4271
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4272
            if (!redirect) {
4273
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4274
                        filename, line_num);
4275
                errors++;
4276
            }
4277
            if (!redirect->feed_filename[0]) {
4278
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4279
                        filename, line_num);
4280
                errors++;
4281
            }
4282
            redirect = NULL;
4283
        } else if (!strcasecmp(cmd, "LoadModule")) {
4284
            get_arg(arg, sizeof(arg), &p);
4285
#ifdef HAVE_DLOPEN
4286
            load_module(arg);
4287
#else
4288
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4289
                    filename, line_num, arg);
4290
            errors++;
4291
#endif
4292
        } else {
4293
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4294
                    filename, line_num, cmd);
4295
            errors++;
4296
        }
4297
    }
4298

    
4299
    fclose(f);
4300
    if (errors)
4301
        return -1;
4302
    else
4303
        return 0;
4304
}
4305

    
4306
static void show_help(void)
4307
{
4308
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4309
           "Hyper fast multi format Audio/Video streaming server\n"
4310
           "\n"
4311
           "-L            : print the LICENSE\n"
4312
           "-h            : this help\n"
4313
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4314
           );
4315
}
4316

    
4317
static void handle_child_exit(int sig)
4318
{
4319
    pid_t pid;
4320
    int status;
4321

    
4322
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4323
        FFStream *feed;
4324

    
4325
        for (feed = first_feed; feed; feed = feed->next) {
4326
            if (feed->pid == pid) {
4327
                int uptime = time(0) - feed->pid_start;
4328

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

    
4332
                if (uptime < 30)
4333
                    /* Turn off any more restarts */
4334
                    feed->child_argv = 0;
4335
            }
4336
        }
4337
    }
4338

    
4339
    need_to_start_children = 1;
4340
}
4341

    
4342
int main(int argc, char **argv)
4343
{
4344
    const char *config_filename;
4345
    int c;
4346
    struct sigaction sigact;
4347

    
4348
    av_register_all();
4349

    
4350
    show_banner(program_name, program_birth_year);
4351

    
4352
    config_filename = "/etc/ffserver.conf";
4353

    
4354
    my_program_name = argv[0];
4355
    my_program_dir = getcwd(0, 0);
4356
    ffserver_daemon = 1;
4357

    
4358
    for(;;) {
4359
        c = getopt(argc, argv, "ndLh?f:");
4360
        if (c == -1)
4361
            break;
4362
        switch(c) {
4363
        case 'L':
4364
            show_license();
4365
            exit(0);
4366
        case '?':
4367
        case 'h':
4368
            show_help();
4369
            exit(0);
4370
        case 'n':
4371
            no_launch = 1;
4372
            break;
4373
        case 'd':
4374
            ffserver_debug = 1;
4375
            ffserver_daemon = 0;
4376
            break;
4377
        case 'f':
4378
            config_filename = optarg;
4379
            break;
4380
        default:
4381
            exit(2);
4382
        }
4383
    }
4384

    
4385
    putenv("http_proxy");               /* Kill the http_proxy */
4386

    
4387
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4388

    
4389
    /* address on which the server will handle HTTP connections */
4390
    my_http_addr.sin_family = AF_INET;
4391
    my_http_addr.sin_port = htons (8080);
4392
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4393

    
4394
    /* address on which the server will handle RTSP connections */
4395
    my_rtsp_addr.sin_family = AF_INET;
4396
    my_rtsp_addr.sin_port = htons (5454);
4397
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4398

    
4399
    nb_max_connections = 5;
4400
    max_bandwidth = 1000;
4401
    first_stream = NULL;
4402
    logfilename[0] = '\0';
4403

    
4404
    memset(&sigact, 0, sizeof(sigact));
4405
    sigact.sa_handler = handle_child_exit;
4406
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4407
    sigaction(SIGCHLD, &sigact, 0);
4408

    
4409
    if (parse_ffconfig(config_filename) < 0) {
4410
        fprintf(stderr, "Incorrect config file - exiting.\n");
4411
        exit(1);
4412
    }
4413

    
4414
    build_file_streams();
4415

    
4416
    build_feed_streams();
4417

    
4418
    compute_bandwidth();
4419

    
4420
    /* put the process in background and detach it from its TTY */
4421
    if (ffserver_daemon) {
4422
        int pid;
4423

    
4424
        pid = fork();
4425
        if (pid < 0) {
4426
            perror("fork");
4427
            exit(1);
4428
        } else if (pid > 0) {
4429
            /* parent : exit */
4430
            exit(0);
4431
        } else {
4432
            /* child */
4433
            setsid();
4434
            chdir("/");
4435
            close(0);
4436
            open("/dev/null", O_RDWR);
4437
            if (strcmp(logfilename, "-") != 0) {
4438
                close(1);
4439
                dup(0);
4440
            }
4441
            close(2);
4442
            dup(0);
4443
        }
4444
    }
4445

    
4446
    /* signal init */
4447
    signal(SIGPIPE, SIG_IGN);
4448

    
4449
    /* open log file if needed */
4450
    if (logfilename[0] != '\0') {
4451
        if (!strcmp(logfilename, "-"))
4452
            logfile = stdout;
4453
        else
4454
            logfile = fopen(logfilename, "w");
4455
    }
4456

    
4457
    if (http_server() < 0) {
4458
        fprintf(stderr, "Could not start server\n");
4459
        exit(1);
4460
    }
4461

    
4462
    return 0;
4463
}