Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 4f90f33a

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

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

    
47
#include "network.h"
48
#include "version.h"
49
#include "ffserver.h"
50
#include "random.h"
51
#include "avstring.h"
52
#include "cmdutils.h"
53

    
54
#undef exit
55

    
56
/* maximum number of simultaneous HTTP connections */
57
#define HTTP_MAX_CONNECTIONS 2000
58

    
59
enum HTTPState {
60
    HTTPSTATE_WAIT_REQUEST,
61
    HTTPSTATE_SEND_HEADER,
62
    HTTPSTATE_SEND_DATA_HEADER,
63
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
64
    HTTPSTATE_SEND_DATA_TRAILER,
65
    HTTPSTATE_RECEIVE_DATA,
66
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
67
    HTTPSTATE_READY,
68

    
69
    RTSPSTATE_WAIT_REQUEST,
70
    RTSPSTATE_SEND_REPLY,
71
    RTSPSTATE_SEND_PACKET,
72
};
73

    
74
const char *http_state[] = {
75
    "HTTP_WAIT_REQUEST",
76
    "HTTP_SEND_HEADER",
77

    
78
    "SEND_DATA_HEADER",
79
    "SEND_DATA",
80
    "SEND_DATA_TRAILER",
81
    "RECEIVE_DATA",
82
    "WAIT_FEED",
83
    "READY",
84

    
85
    "RTSP_WAIT_REQUEST",
86
    "RTSP_SEND_REPLY",
87
    "RTSP_SEND_PACKET",
88
};
89

    
90
#define IOBUFFER_INIT_SIZE 8192
91

    
92
/* timeouts are in ms */
93
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
94
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
95

    
96
#define SYNC_TIMEOUT (10 * 1000)
97

    
98
typedef struct {
99
    int64_t count1, count2;
100
    int64_t time1, time2;
101
} DataRateData;
102

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

    
148
    /* RTSP state specific */
149
    uint8_t *pb_buffer; /* XXX: use that in all the code */
150
    ByteIOContext *pb;
151
    int seq; /* RTSP sequence number */
152

    
153
    /* RTP state specific */
154
    enum RTSPProtocol rtp_protocol;
155
    char session_id[32]; /* session id */
156
    AVFormatContext *rtp_ctx[MAX_STREAMS];
157

    
158
    /* RTP/UDP specific */
159
    URLContext *rtp_handles[MAX_STREAMS];
160

    
161
    /* RTP/TCP specific */
162
    struct HTTPContext *rtsp_c;
163
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
164
} HTTPContext;
165

    
166
static AVFrame dummy_frame;
167

    
168
/* each generated stream is described here */
169
enum StreamType {
170
    STREAM_TYPE_LIVE,
171
    STREAM_TYPE_STATUS,
172
    STREAM_TYPE_REDIRECT,
173
};
174

    
175
enum IPAddressAction {
176
    IP_ALLOW = 1,
177
    IP_DENY,
178
};
179

    
180
typedef struct IPAddressACL {
181
    struct IPAddressACL *next;
182
    enum IPAddressAction action;
183
    /* These are in host order */
184
    struct in_addr first;
185
    struct in_addr last;
186
} IPAddressACL;
187

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

    
224
    /* feed specific */
225
    int feed_opened;     /* true if someone is writing to the feed */
226
    int is_feed;         /* true if it is a feed */
227
    int readonly;        /* True if writing is prohibited to the file */
228
    int conns_served;
229
    int64_t bytes_served;
230
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
231
    int64_t feed_write_index;   /* current write position in feed (it wraps round) */
232
    int64_t feed_size;          /* current size of feed */
233
    struct FFStream *next_feed;
234
} FFStream;
235

    
236
typedef struct FeedData {
237
    long long data_count;
238
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
239
} FeedData;
240

    
241
static struct sockaddr_in my_http_addr;
242
static struct sockaddr_in my_rtsp_addr;
243

    
244
static char logfilename[1024];
245
static HTTPContext *first_http_ctx;
246
static FFStream *first_feed;   /* contains only feeds */
247
static FFStream *first_stream; /* contains all streams, including feeds */
248

    
249
static void new_connection(int server_fd, int is_rtsp);
250
static void close_connection(HTTPContext *c);
251

    
252
/* HTTP handling */
253
static int handle_connection(HTTPContext *c);
254
static int http_parse_request(HTTPContext *c);
255
static int http_send_data(HTTPContext *c);
256
static void compute_stats(HTTPContext *c);
257
static int open_input_stream(HTTPContext *c, const char *info);
258
static int http_start_receive_data(HTTPContext *c);
259
static int http_receive_data(HTTPContext *c);
260

    
261
/* RTSP handling */
262
static int rtsp_parse_request(HTTPContext *c);
263
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
264
static void rtsp_cmd_options(HTTPContext *c, const char *url);
265
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
266
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
267
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
268
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
269

    
270
/* SDP handling */
271
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
272
                                   struct in_addr my_ip);
273

    
274
/* RTP handling */
275
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
276
                                       FFStream *stream, const char *session_id,
277
                                       enum RTSPProtocol rtp_protocol);
278
static int rtp_new_av_stream(HTTPContext *c,
279
                             int stream_index, struct sockaddr_in *dest_addr,
280
                             HTTPContext *rtsp_c);
281

    
282
static const char *my_program_name;
283
static const char *my_program_dir;
284

    
285
static int ffserver_debug;
286
static int ffserver_daemon;
287
static int no_launch;
288
static int need_to_start_children;
289

    
290
static int nb_max_connections;
291
static int nb_connections;
292

    
293
static int max_bandwidth;
294
static int current_bandwidth;
295

    
296
static int64_t cur_time;           // Making this global saves on passing it around everywhere
297

    
298
static AVRandomState random_state;
299

    
300
static FILE *logfile = NULL;
301

    
302
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
303
{
304
    va_list ap;
305
    va_start(ap, fmt);
306

    
307
    if (logfile) {
308
        vfprintf(logfile, fmt, ap);
309
        fflush(logfile);
310
    }
311
    va_end(ap);
312
}
313

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

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

    
328
static void log_connection(HTTPContext *c)
329
{
330
    char buf2[32];
331

    
332
    if (c->suppress_log)
333
        return;
334

    
335
    http_log("%s - - [%s] \"%s %s %s\" %d %"PRId64"\n",
336
             inet_ntoa(c->from_addr.sin_addr),
337
             ctime1(buf2), c->method, c->url,
338
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
339
}
340

    
341
static void update_datarate(DataRateData *drd, int64_t count)
342
{
343
    if (!drd->time1 && !drd->count1) {
344
        drd->time1 = drd->time2 = cur_time;
345
        drd->count1 = drd->count2 = count;
346
    } else if (cur_time - drd->time2 > 5000) {
347
        drd->time1 = drd->time2;
348
        drd->count1 = drd->count2;
349
        drd->time2 = cur_time;
350
        drd->count2 = count;
351
    }
352
}
353

    
354
/* In bytes per second */
355
static int compute_datarate(DataRateData *drd, int64_t count)
356
{
357
    if (cur_time == drd->time1)
358
        return 0;
359

    
360
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
361
}
362

    
363

    
364
static void start_children(FFStream *feed)
365
{
366
    if (no_launch)
367
        return;
368

    
369
    for (; feed; feed = feed->next) {
370
        if (feed->child_argv && !feed->pid) {
371
            feed->pid_start = time(0);
372

    
373
            feed->pid = fork();
374

    
375
            if (feed->pid < 0) {
376
                fprintf(stderr, "Unable to create children\n");
377
                exit(1);
378
            }
379
            if (!feed->pid) {
380
                /* In child */
381
                char pathname[1024];
382
                char *slash;
383
                int i;
384

    
385
                for (i = 3; i < 256; i++)
386
                    close(i);
387

    
388
                if (!ffserver_debug) {
389
                    i = open("/dev/null", O_RDWR);
390
                    if (i)
391
                        dup2(i, 0);
392
                    dup2(i, 1);
393
                    dup2(i, 2);
394
                    if (i)
395
                        close(i);
396
                }
397

    
398
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
399

    
400
                slash = strrchr(pathname, '/');
401
                if (!slash)
402
                    slash = pathname;
403
                else
404
                    slash++;
405
                strcpy(slash, "ffmpeg");
406

    
407
                /* This is needed to make relative pathnames work */
408
                chdir(my_program_dir);
409

    
410
                signal(SIGPIPE, SIG_DFL);
411

    
412
                execvp(pathname, feed->child_argv);
413

    
414
                _exit(1);
415
            }
416
        }
417
    }
418
}
419

    
420
/* open a listening socket */
421
static int socket_open_listen(struct sockaddr_in *my_addr)
422
{
423
    int server_fd, tmp;
424

    
425
    server_fd = socket(AF_INET,SOCK_STREAM,0);
426
    if (server_fd < 0) {
427
        perror ("socket");
428
        return -1;
429
    }
430

    
431
    tmp = 1;
432
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
433

    
434
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
435
        char bindmsg[32];
436
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
437
        perror (bindmsg);
438
        closesocket(server_fd);
439
        return -1;
440
    }
441

    
442
    if (listen (server_fd, 5) < 0) {
443
        perror ("listen");
444
        closesocket(server_fd);
445
        return -1;
446
    }
447
    ff_socket_nonblock(server_fd, 1);
448

    
449
    return server_fd;
450
}
451

    
452
/* start all multicast streams */
453
static void start_multicast(void)
454
{
455
    FFStream *stream;
456
    char session_id[32];
457
    HTTPContext *rtp_c;
458
    struct sockaddr_in dest_addr;
459
    int default_port, stream_index;
460

    
461
    default_port = 6000;
462
    for(stream = first_stream; stream != NULL; stream = stream->next) {
463
        if (stream->is_multicast) {
464
            /* open the RTP connection */
465
            snprintf(session_id, sizeof(session_id), "%08x%08x",
466
                     av_random(&random_state), av_random(&random_state));
467

    
468
            /* choose a port if none given */
469
            if (stream->multicast_port == 0) {
470
                stream->multicast_port = default_port;
471
                default_port += 100;
472
            }
473

    
474
            dest_addr.sin_family = AF_INET;
475
            dest_addr.sin_addr = stream->multicast_ip;
476
            dest_addr.sin_port = htons(stream->multicast_port);
477

    
478
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
479
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
480
            if (!rtp_c)
481
                continue;
482

    
483
            if (open_input_stream(rtp_c, "") < 0) {
484
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
485
                        stream->filename);
486
                continue;
487
            }
488

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

    
501
            /* change state to send data */
502
            rtp_c->state = HTTPSTATE_SEND_DATA;
503
        }
504
    }
505
}
506

    
507
/* main loop of the http server */
508
static int http_server(void)
509
{
510
    int server_fd, ret, rtsp_server_fd, delay, delay1;
511
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
512
    HTTPContext *c, *c_next;
513

    
514
    server_fd = socket_open_listen(&my_http_addr);
515
    if (server_fd < 0)
516
        return -1;
517

    
518
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
519
    if (rtsp_server_fd < 0)
520
        return -1;
521

    
522
    http_log("ffserver started.\n");
523

    
524
    start_children(first_feed);
525

    
526
    first_http_ctx = NULL;
527
    nb_connections = 0;
528

    
529
    start_multicast();
530

    
531
    for(;;) {
532
        poll_entry = poll_table;
533
        poll_entry->fd = server_fd;
534
        poll_entry->events = POLLIN;
535
        poll_entry++;
536

    
537
        poll_entry->fd = rtsp_server_fd;
538
        poll_entry->events = POLLIN;
539
        poll_entry++;
540

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

    
591
        /* wait for an event on one connection. We poll at least every
592
           second to handle timeouts */
593
        do {
594
            ret = poll(poll_table, poll_entry - poll_table, delay);
595
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
596
                ff_neterrno() != FF_NETERROR(EINTR))
597
                return -1;
598
        } while (ret < 0);
599

    
600
        cur_time = av_gettime() / 1000;
601

    
602
        if (need_to_start_children) {
603
            need_to_start_children = 0;
604
            start_children(first_feed);
605
        }
606

    
607
        /* now handle the events */
608
        for(c = first_http_ctx; c != NULL; c = c_next) {
609
            c_next = c->next;
610
            if (handle_connection(c) < 0) {
611
                /* close and free the connection */
612
                log_connection(c);
613
                close_connection(c);
614
            }
615
        }
616

    
617
        poll_entry = poll_table;
618
        /* new HTTP connection request ? */
619
        if (poll_entry->revents & POLLIN)
620
            new_connection(server_fd, 0);
621
        poll_entry++;
622
        /* new RTSP connection request ? */
623
        if (poll_entry->revents & POLLIN)
624
            new_connection(rtsp_server_fd, 1);
625
    }
626
}
627

    
628
/* start waiting for a new HTTP/RTSP request */
629
static void start_wait_request(HTTPContext *c, int is_rtsp)
630
{
631
    c->buffer_ptr = c->buffer;
632
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
633

    
634
    if (is_rtsp) {
635
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
636
        c->state = RTSPSTATE_WAIT_REQUEST;
637
    } else {
638
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
639
        c->state = HTTPSTATE_WAIT_REQUEST;
640
    }
641
}
642

    
643
static void new_connection(int server_fd, int is_rtsp)
644
{
645
    struct sockaddr_in from_addr;
646
    int fd, len;
647
    HTTPContext *c = NULL;
648

    
649
    len = sizeof(from_addr);
650
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
651
                &len);
652
    if (fd < 0)
653
        return;
654
    ff_socket_nonblock(fd, 1);
655

    
656
    /* XXX: should output a warning page when coming
657
       close to the connection limit */
658
    if (nb_connections >= nb_max_connections)
659
        goto fail;
660

    
661
    /* add a new connection */
662
    c = av_mallocz(sizeof(HTTPContext));
663
    if (!c)
664
        goto fail;
665

    
666
    c->fd = fd;
667
    c->poll_entry = NULL;
668
    c->from_addr = from_addr;
669
    c->buffer_size = IOBUFFER_INIT_SIZE;
670
    c->buffer = av_malloc(c->buffer_size);
671
    if (!c->buffer)
672
        goto fail;
673

    
674
    c->next = first_http_ctx;
675
    first_http_ctx = c;
676
    nb_connections++;
677

    
678
    start_wait_request(c, is_rtsp);
679

    
680
    return;
681

    
682
 fail:
683
    if (c) {
684
        av_free(c->buffer);
685
        av_free(c);
686
    }
687
    closesocket(fd);
688
}
689

    
690
static void close_connection(HTTPContext *c)
691
{
692
    HTTPContext **cp, *c1;
693
    int i, nb_streams;
694
    AVFormatContext *ctx;
695
    URLContext *h;
696
    AVStream *st;
697

    
698
    /* remove connection from list */
699
    cp = &first_http_ctx;
700
    while ((*cp) != NULL) {
701
        c1 = *cp;
702
        if (c1 == c)
703
            *cp = c->next;
704
        else
705
            cp = &c1->next;
706
    }
707

    
708
    /* remove references, if any (XXX: do it faster) */
709
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
710
        if (c1->rtsp_c == c)
711
            c1->rtsp_c = NULL;
712
    }
713

    
714
    /* remove connection associated resources */
715
    if (c->fd >= 0)
716
        closesocket(c->fd);
717
    if (c->fmt_in) {
718
        /* close each frame parser */
719
        for(i=0;i<c->fmt_in->nb_streams;i++) {
720
            st = c->fmt_in->streams[i];
721
            if (st->codec->codec)
722
                avcodec_close(st->codec);
723
        }
724
        av_close_input_file(c->fmt_in);
725
    }
726

    
727
    /* free RTP output streams if any */
728
    nb_streams = 0;
729
    if (c->stream)
730
        nb_streams = c->stream->nb_streams;
731

    
732
    for(i=0;i<nb_streams;i++) {
733
        ctx = c->rtp_ctx[i];
734
        if (ctx) {
735
            av_write_trailer(ctx);
736
            av_free(ctx);
737
        }
738
        h = c->rtp_handles[i];
739
        if (h)
740
            url_close(h);
741
    }
742

    
743
    ctx = &c->fmt_ctx;
744

    
745
    if (!c->last_packet_sent) {
746
        if (ctx->oformat) {
747
            /* prepare header */
748
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
749
                av_write_trailer(ctx);
750
                url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
751
            }
752
        }
753
    }
754

    
755
    for(i=0; i<ctx->nb_streams; i++)
756
        av_free(ctx->streams[i]);
757

    
758
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
759
        current_bandwidth -= c->stream->bandwidth;
760

    
761
    /* signal that there is no feed if we are the feeder socket */
762
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
763
        c->stream->feed_opened = 0;
764
        close(c->feed_fd);
765
    }
766

    
767
    av_freep(&c->pb_buffer);
768
    av_freep(&c->packet_buffer);
769
    av_free(c->buffer);
770
    av_free(c);
771
    nb_connections--;
772
}
773

    
774
static int handle_connection(HTTPContext *c)
775
{
776
    int len, ret;
777

    
778
    switch(c->state) {
779
    case HTTPSTATE_WAIT_REQUEST:
780
    case RTSPSTATE_WAIT_REQUEST:
781
        /* timeout ? */
782
        if ((c->timeout - cur_time) < 0)
783
            return -1;
784
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
785
            return -1;
786

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

    
821
    case HTTPSTATE_SEND_HEADER:
822
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
823
            return -1;
824

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

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

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

    
887
        /* nothing to do, we'll be waken up by incoming feed packets */
888
        break;
889

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

    
951
static int extract_rates(char *rates, int ratelen, const char *request)
952
{
953
    const char *p;
954

    
955
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
956
        if (strncasecmp(p, "Pragma:", 7) == 0) {
957
            const char *q = p + 7;
958

    
959
            while (*q && *q != '\n' && isspace(*q))
960
                q++;
961

    
962
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
963
                int stream_no;
964
                int rate_no;
965

    
966
                q += 20;
967

    
968
                memset(rates, 0xff, ratelen);
969

    
970
                while (1) {
971
                    while (*q && *q != '\n' && *q != ':')
972
                        q++;
973

    
974
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
975
                        break;
976

    
977
                    stream_no--;
978
                    if (stream_no < ratelen && stream_no >= 0)
979
                        rates[stream_no] = rate_no;
980

    
981
                    while (*q && *q != '\n' && !isspace(*q))
982
                        q++;
983
                }
984

    
985
                return 1;
986
            }
987
        }
988
        p = strchr(p, '\n');
989
        if (!p)
990
            break;
991

    
992
        p++;
993
    }
994

    
995
    return 0;
996
}
997

    
998
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
999
{
1000
    int i;
1001
    int best_bitrate = 100000000;
1002
    int best = -1;
1003

    
1004
    for (i = 0; i < feed->nb_streams; i++) {
1005
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1006

    
1007
        if (feed_codec->codec_id != codec->codec_id ||
1008
            feed_codec->sample_rate != codec->sample_rate ||
1009
            feed_codec->width != codec->width ||
1010
            feed_codec->height != codec->height)
1011
            continue;
1012

    
1013
        /* Potential stream */
1014

    
1015
        /* We want the fastest stream less than bit_rate, or the slowest
1016
         * faster than bit_rate
1017
         */
1018

    
1019
        if (feed_codec->bit_rate <= bit_rate) {
1020
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1021
                best_bitrate = feed_codec->bit_rate;
1022
                best = i;
1023
            }
1024
        } else {
1025
            if (feed_codec->bit_rate < best_bitrate) {
1026
                best_bitrate = feed_codec->bit_rate;
1027
                best = i;
1028
            }
1029
        }
1030
    }
1031

    
1032
    return best;
1033
}
1034

    
1035
static int modify_current_stream(HTTPContext *c, char *rates)
1036
{
1037
    int i;
1038
    FFStream *req = c->stream;
1039
    int action_required = 0;
1040

    
1041
    /* Not much we can do for a feed */
1042
    if (!req->feed)
1043
        return 0;
1044

    
1045
    for (i = 0; i < req->nb_streams; i++) {
1046
        AVCodecContext *codec = req->streams[i]->codec;
1047

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

    
1066
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1067
            action_required = 1;
1068
    }
1069

    
1070
    return action_required;
1071
}
1072

    
1073

    
1074
static void do_switch_stream(HTTPContext *c, int i)
1075
{
1076
    if (c->switch_feed_streams[i] >= 0) {
1077
#ifdef PHILIP
1078
        c->feed_streams[i] = c->switch_feed_streams[i];
1079
#endif
1080

    
1081
        /* Now update the stream */
1082
    }
1083
    c->switch_feed_streams[i] = -1;
1084
}
1085

    
1086
/* XXX: factorize in utils.c ? */
1087
/* XXX: take care with different space meaning */
1088
static void skip_spaces(const char **pp)
1089
{
1090
    const char *p;
1091
    p = *pp;
1092
    while (*p == ' ' || *p == '\t')
1093
        p++;
1094
    *pp = p;
1095
}
1096

    
1097
static void get_word(char *buf, int buf_size, const char **pp)
1098
{
1099
    const char *p;
1100
    char *q;
1101

    
1102
    p = *pp;
1103
    skip_spaces(&p);
1104
    q = buf;
1105
    while (!isspace(*p) && *p != '\0') {
1106
        if ((q - buf) < buf_size - 1)
1107
            *q++ = *p;
1108
        p++;
1109
    }
1110
    if (buf_size > 0)
1111
        *q = '\0';
1112
    *pp = p;
1113
}
1114

    
1115
static int validate_acl(FFStream *stream, HTTPContext *c)
1116
{
1117
    enum IPAddressAction last_action = IP_DENY;
1118
    IPAddressACL *acl;
1119
    struct in_addr *src = &c->from_addr.sin_addr;
1120
    unsigned long src_addr = src->s_addr;
1121

    
1122
    for (acl = stream->acl; acl; acl = acl->next) {
1123
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1124
            return (acl->action == IP_ALLOW) ? 1 : 0;
1125
        last_action = acl->action;
1126
    }
1127

    
1128
    /* Nothing matched, so return not the last action */
1129
    return (last_action == IP_DENY) ? 1 : 0;
1130
}
1131

    
1132
/* compute the real filename of a file by matching it without its
1133
   extensions to all the stream filenames */
1134
static void compute_real_filename(char *filename, int max_size)
1135
{
1136
    char file1[1024];
1137
    char file2[1024];
1138
    char *p;
1139
    FFStream *stream;
1140

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

    
1158
enum RedirType {
1159
    REDIR_NONE,
1160
    REDIR_ASX,
1161
    REDIR_RAM,
1162
    REDIR_ASF,
1163
    REDIR_RTSP,
1164
    REDIR_SDP,
1165
};
1166

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

    
1183
    p = c->buffer;
1184
    get_word(cmd, sizeof(cmd), (const char **)&p);
1185
    av_strlcpy(c->method, cmd, sizeof(c->method));
1186

    
1187
    if (!strcmp(cmd, "GET"))
1188
        c->post = 0;
1189
    else if (!strcmp(cmd, "POST"))
1190
        c->post = 1;
1191
    else
1192
        return -1;
1193

    
1194
    get_word(url, sizeof(url), (const char **)&p);
1195
    av_strlcpy(c->url, url, sizeof(c->url));
1196

    
1197
    get_word(protocol, sizeof(protocol), (const char **)&p);
1198
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1199
        return -1;
1200

    
1201
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1202

    
1203
    if (ffserver_debug)
1204
        http_log("New connection: %s %s\n", cmd, url);
1205

    
1206
    /* find the filename and the optional info string in the request */
1207
    p = strchr(url, '?');
1208
    if (p) {
1209
        av_strlcpy(info, p, sizeof(info));
1210
        *p = '\0';
1211
    } else
1212
        info[0] = '\0';
1213

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

    
1216
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1217
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1218
            useragent = p + 11;
1219
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1220
                useragent++;
1221
            break;
1222
        }
1223
        p = strchr(p, '\n');
1224
        if (!p)
1225
            break;
1226

    
1227
        p++;
1228
    }
1229

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

    
1249
    // "redirect" / request to index.html
1250
    if (!strlen(filename))
1251
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1252

    
1253
    stream = first_stream;
1254
    while (stream != NULL) {
1255
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1256
            break;
1257
        stream = stream->next;
1258
    }
1259
    if (stream == NULL) {
1260
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1261
        goto send_error;
1262
    }
1263

    
1264
    c->stream = stream;
1265
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1266
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1267

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

    
1279
        /* prepare output buffer */
1280
        c->buffer_ptr = c->buffer;
1281
        c->buffer_end = q;
1282
        c->state = HTTPSTATE_SEND_HEADER;
1283
        return 0;
1284
    }
1285

    
1286
    /* If this is WMP, get the rate information */
1287
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1288
        if (modify_current_stream(c, ratebuf)) {
1289
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1290
                if (c->switch_feed_streams[i] >= 0)
1291
                    do_switch_stream(c, i);
1292
            }
1293
        }
1294
    }
1295

    
1296
    /* If already streaming this feed, do not let start another feeder. */
1297
    if (stream->feed_opened) {
1298
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1299
        goto send_error;
1300
    }
1301

    
1302
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1303
        current_bandwidth += stream->bandwidth;
1304

    
1305
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1306
        c->http_error = 200;
1307
        q = c->buffer;
1308
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1309
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1310
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1311
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1312
        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");
1313
        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",
1314
            current_bandwidth, max_bandwidth);
1315
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1316

    
1317
        /* prepare output buffer */
1318
        c->buffer_ptr = c->buffer;
1319
        c->buffer_end = q;
1320
        c->state = HTTPSTATE_SEND_HEADER;
1321
        return 0;
1322
    }
1323

    
1324
    if (redir_type != REDIR_NONE) {
1325
        char *hostinfo = 0;
1326

    
1327
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1328
            if (strncasecmp(p, "Host:", 5) == 0) {
1329
                hostinfo = p + 5;
1330
                break;
1331
            }
1332
            p = strchr(p, '\n');
1333
            if (!p)
1334
                break;
1335

    
1336
            p++;
1337
        }
1338

    
1339
        if (hostinfo) {
1340
            char *eoh;
1341
            char hostbuf[260];
1342

    
1343
            while (isspace(*hostinfo))
1344
                hostinfo++;
1345

    
1346
            eoh = strchr(hostinfo, '\n');
1347
            if (eoh) {
1348
                if (eoh[-1] == '\r')
1349
                    eoh--;
1350

    
1351
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1352
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1353
                    hostbuf[eoh - hostinfo] = 0;
1354

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

    
1407
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1408
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1409
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1410

    
1411
                            len = sizeof(my_addr);
1412
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1413

    
1414
                            /* XXX: should use a dynamic buffer */
1415
                            sdp_data_size = prepare_sdp_description(stream,
1416
                                                                    &sdp_data,
1417
                                                                    my_addr.sin_addr);
1418
                            if (sdp_data_size > 0) {
1419
                                memcpy(q, sdp_data, sdp_data_size);
1420
                                q += sdp_data_size;
1421
                                *q = '\0';
1422
                                av_free(sdp_data);
1423
                            }
1424
                        }
1425
                        break;
1426
                    default:
1427
                        abort();
1428
                        break;
1429
                    }
1430

    
1431
                    /* prepare output buffer */
1432
                    c->buffer_ptr = c->buffer;
1433
                    c->buffer_end = q;
1434
                    c->state = HTTPSTATE_SEND_HEADER;
1435
                    return 0;
1436
                }
1437
            }
1438
        }
1439

    
1440
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1441
        goto send_error;
1442
    }
1443

    
1444
    stream->conns_served++;
1445

    
1446
    /* XXX: add there authenticate and IP match */
1447

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

    
1457
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1458
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1459
                    logline = p;
1460
                    break;
1461
                }
1462
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1463
                    client_id = strtol(p + 18, 0, 10);
1464
                p = strchr(p, '\n');
1465
                if (!p)
1466
                    break;
1467

    
1468
                p++;
1469
            }
1470

    
1471
            if (logline) {
1472
                char *eol = strchr(logline, '\n');
1473

    
1474
                logline += 17;
1475

    
1476
                if (eol) {
1477
                    if (eol[-1] == '\r')
1478
                        eol--;
1479
                    http_log("%.*s\n", (int) (eol - logline), logline);
1480
                    c->suppress_log = 1;
1481
                }
1482
            }
1483

    
1484
#ifdef DEBUG_WMP
1485
            http_log("\nGot request:\n%s\n", c->buffer);
1486
#endif
1487

    
1488
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1489
                HTTPContext *wmpc;
1490

    
1491
                /* Now we have to find the client_id */
1492
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1493
                    if (wmpc->wmp_client_id == client_id)
1494
                        break;
1495
                }
1496

    
1497
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1498
                    wmpc->switch_pending = 1;
1499
            }
1500

    
1501
            snprintf(msg, sizeof(msg), "POST command not handled");
1502
            c->stream = 0;
1503
            goto send_error;
1504
        }
1505
        if (http_start_receive_data(c) < 0) {
1506
            snprintf(msg, sizeof(msg), "could not open feed");
1507
            goto send_error;
1508
        }
1509
        c->http_error = 0;
1510
        c->state = HTTPSTATE_RECEIVE_DATA;
1511
        return 0;
1512
    }
1513

    
1514
#ifdef DEBUG_WMP
1515
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1516
        http_log("\nGot request:\n%s\n", c->buffer);
1517
#endif
1518

    
1519
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1520
        goto send_stats;
1521

    
1522
    /* open input stream */
1523
    if (open_input_stream(c, info) < 0) {
1524
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1525
        goto send_error;
1526
    }
1527

    
1528
    /* prepare http header */
1529
    q = c->buffer;
1530
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1531
    mime_type = c->stream->fmt->mime_type;
1532
    if (!mime_type)
1533
        mime_type = "application/x-octet-stream";
1534
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1535

    
1536
    /* for asf, we need extra headers */
1537
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1538
        /* Need to allocate a client id */
1539

    
1540
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1541

    
1542
        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);
1543
    }
1544
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1545
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1546

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

    
1564
    /* prepare output buffer */
1565
    c->buffer_ptr = c->buffer;
1566
    c->buffer_end = q;
1567
    c->state = HTTPSTATE_SEND_HEADER;
1568
    return 0;
1569
 send_stats:
1570
    compute_stats(c);
1571
    c->http_error = 200; /* horrible : we use this value to avoid
1572
                            going to the send data state */
1573
    c->state = HTTPSTATE_SEND_HEADER;
1574
    return 0;
1575
}
1576

    
1577
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1578
{
1579
    static const char *suffix = " kMGTP";
1580
    const char *s;
1581

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

    
1584
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1585
}
1586

    
1587
static void compute_stats(HTTPContext *c)
1588
{
1589
    HTTPContext *c1;
1590
    FFStream *stream;
1591
    char *p;
1592
    time_t ti;
1593
    int i, len;
1594
    ByteIOContext pb1, *pb = &pb1;
1595

    
1596
    if (url_open_dyn_buf(pb) < 0) {
1597
        /* XXX: return an error ? */
1598
        c->buffer_ptr = c->buffer;
1599
        c->buffer_end = c->buffer;
1600
        return;
1601
    }
1602

    
1603
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1604
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1605
    url_fprintf(pb, "Pragma: no-cache\r\n");
1606
    url_fprintf(pb, "\r\n");
1607

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

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

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

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

    
1707
    stream = first_stream;
1708
    while (stream != NULL) {
1709
        if (stream->feed == stream) {
1710
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1711
            if (stream->pid) {
1712
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1713

    
1714
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1715
                {
1716
                    FILE *pid_stat;
1717
                    char ps_cmd[64];
1718

    
1719
                    /* This is somewhat linux specific I guess */
1720
                    snprintf(ps_cmd, sizeof(ps_cmd),
1721
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1722
                             stream->pid);
1723

    
1724
                    pid_stat = popen(ps_cmd, "r");
1725
                    if (pid_stat) {
1726
                        char cpuperc[10];
1727
                        char cpuused[64];
1728

    
1729
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1730
                                   cpuused) == 2) {
1731
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1732
                                         cpuperc, cpuused);
1733
                        }
1734
                        fclose(pid_stat);
1735
                    }
1736
                }
1737
#endif
1738

    
1739
                url_fprintf(pb, "<p>");
1740
            }
1741
            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");
1742

    
1743
            for (i = 0; i < stream->nb_streams; i++) {
1744
                AVStream *st = stream->streams[i];
1745
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1746
                const char *type = "unknown";
1747
                char parameters[64];
1748

    
1749
                parameters[0] = 0;
1750

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

    
1769
        }
1770
        stream = stream->next;
1771
    }
1772

    
1773
#if 0
1774
    {
1775
        float avg;
1776
        AVCodecContext *enc;
1777
        char buf[1024];
1778

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

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

    
1803
    /* connection status */
1804
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1805

    
1806
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1807
                 nb_connections, nb_max_connections);
1808

    
1809
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1810
                 current_bandwidth, max_bandwidth);
1811

    
1812
    url_fprintf(pb, "<TABLE>\n");
1813
    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");
1814
    c1 = first_http_ctx;
1815
    i = 0;
1816
    while (c1 != NULL) {
1817
        int bitrate;
1818
        int j;
1819

    
1820
        bitrate = 0;
1821
        if (c1->stream) {
1822
            for (j = 0; j < c1->stream->nb_streams; j++) {
1823
                if (!c1->stream->feed)
1824
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1825
                else if (c1->feed_streams[j] >= 0)
1826
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1827
            }
1828
        }
1829

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

    
1849
    /* date */
1850
    ti = time(NULL);
1851
    p = ctime(&ti);
1852
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1853
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1854

    
1855
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1856
    c->buffer_ptr = c->pb_buffer;
1857
    c->buffer_end = c->pb_buffer + len;
1858
}
1859

    
1860
/* check if the parser needs to be opened for stream i */
1861
static void open_parser(AVFormatContext *s, int i)
1862
{
1863
    AVStream *st = s->streams[i];
1864
    AVCodec *codec;
1865

    
1866
    if (!st->codec->codec) {
1867
        codec = avcodec_find_decoder(st->codec->codec_id);
1868
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1869
            st->codec->parse_only = 1;
1870
            if (avcodec_open(st->codec, codec) < 0)
1871
                st->codec->parse_only = 0;
1872
        }
1873
    }
1874
}
1875

    
1876
static int open_input_stream(HTTPContext *c, const char *info)
1877
{
1878
    char buf[128];
1879
    char input_filename[1024];
1880
    AVFormatContext *s;
1881
    int buf_size, i;
1882
    int64_t stream_pos;
1883

    
1884
    /* find file name */
1885
    if (c->stream->feed) {
1886
        strcpy(input_filename, c->stream->feed->feed_filename);
1887
        buf_size = FFM_PACKET_SIZE;
1888
        /* compute position (absolute time) */
1889
        if (find_info_tag(buf, sizeof(buf), "date", info))
1890
            stream_pos = parse_date(buf, 0);
1891
        else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1892
            int prebuffer = strtol(buf, 0, 10);
1893
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1894
        } else
1895
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1896
    } else {
1897
        strcpy(input_filename, c->stream->feed_filename);
1898
        buf_size = 0;
1899
        /* compute position (relative time) */
1900
        if (find_info_tag(buf, sizeof(buf), "date", info))
1901
            stream_pos = parse_date(buf, 1);
1902
        else
1903
            stream_pos = 0;
1904
    }
1905
    if (input_filename[0] == '\0')
1906
        return -1;
1907

    
1908
#if 0
1909
    { time_t when = stream_pos / 1000000;
1910
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1911
    }
1912
#endif
1913

    
1914
    /* open stream */
1915
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1916
                           buf_size, c->stream->ap_in) < 0) {
1917
        http_log("%s not found", input_filename);
1918
        return -1;
1919
    }
1920
    c->fmt_in = s;
1921
    av_find_stream_info(c->fmt_in);
1922

    
1923
    /* open each parser */
1924
    for(i=0;i<s->nb_streams;i++)
1925
        open_parser(s, i);
1926

    
1927
    /* choose stream as clock source (we favorize video stream if
1928
       present) for packet sending */
1929
    c->pts_stream_index = 0;
1930
    for(i=0;i<c->stream->nb_streams;i++) {
1931
        if (c->pts_stream_index == 0 &&
1932
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1933
            c->pts_stream_index = i;
1934
        }
1935
    }
1936

    
1937
#if 1
1938
    if (c->fmt_in->iformat->read_seek)
1939
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1940
#endif
1941
    /* set the start time (needed for maxtime and RTP packet timing) */
1942
    c->start_time = cur_time;
1943
    c->first_pts = AV_NOPTS_VALUE;
1944
    return 0;
1945
}
1946

    
1947
/* return the server clock (in us) */
1948
static int64_t get_server_clock(HTTPContext *c)
1949
{
1950
    /* compute current pts value from system time */
1951
    return (cur_time - c->start_time) * 1000;
1952
}
1953

    
1954
/* return the estimated time at which the current packet must be sent
1955
   (in us) */
1956
static int64_t get_packet_send_clock(HTTPContext *c)
1957
{
1958
    int bytes_left, bytes_sent, frame_bytes;
1959

    
1960
    frame_bytes = c->cur_frame_bytes;
1961
    if (frame_bytes <= 0)
1962
        return c->cur_pts;
1963
    else {
1964
        bytes_left = c->buffer_end - c->buffer_ptr;
1965
        bytes_sent = frame_bytes - bytes_left;
1966
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1967
    }
1968
}
1969

    
1970

    
1971
static int http_prepare_data(HTTPContext *c)
1972
{
1973
    int i, len, ret;
1974
    AVFormatContext *ctx;
1975

    
1976
    av_freep(&c->pb_buffer);
1977
    switch(c->state) {
1978
    case HTTPSTATE_SEND_DATA_HEADER:
1979
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1980
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
1981
                   sizeof(c->fmt_ctx.author));
1982
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
1983
                   sizeof(c->fmt_ctx.comment));
1984
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
1985
                   sizeof(c->fmt_ctx.copyright));
1986
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
1987
                   sizeof(c->fmt_ctx.title));
1988

    
1989
        /* open output stream by using specified codecs */
1990
        c->fmt_ctx.oformat = c->stream->fmt;
1991
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
1992
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1993
            AVStream *st;
1994
            AVStream *src;
1995
            st = av_mallocz(sizeof(AVStream));
1996
            st->codec= avcodec_alloc_context();
1997
            c->fmt_ctx.streams[i] = st;
1998
            /* if file or feed, then just take streams from FFStream struct */
1999
            if (!c->stream->feed ||
2000
                c->stream->feed == c->stream)
2001
                src = c->stream->streams[i];
2002
            else
2003
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2004

    
2005
            *st = *src;
2006
            st->priv_data = 0;
2007
            st->codec->frame_number = 0; /* XXX: should be done in
2008
                                           AVStream, not in codec */
2009
            /* I'm pretty sure that this is not correct...
2010
             * However, without it, we crash
2011
             */
2012
            st->codec->coded_frame = &dummy_frame;
2013
        }
2014
        c->got_key_frame = 0;
2015

    
2016
        /* prepare header and save header data in a stream */
2017
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2018
            /* XXX: potential leak */
2019
            return -1;
2020
        }
2021
        c->fmt_ctx.pb.is_streamed = 1;
2022

    
2023
        av_set_parameters(&c->fmt_ctx, NULL);
2024
        if (av_write_header(&c->fmt_ctx) < 0)
2025
            return -1;
2026

    
2027
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2028
        c->buffer_ptr = c->pb_buffer;
2029
        c->buffer_end = c->pb_buffer + len;
2030

    
2031
        c->state = HTTPSTATE_SEND_DATA;
2032
        c->last_packet_sent = 0;
2033
        break;
2034
    case HTTPSTATE_SEND_DATA:
2035
        /* find a new packet */
2036
        {
2037
            AVPacket pkt;
2038

    
2039
            /* read a packet from the input stream */
2040
            if (c->stream->feed)
2041
                ffm_set_write_index(c->fmt_in,
2042
                                    c->stream->feed->feed_write_index,
2043
                                    c->stream->feed->feed_size);
2044

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

    
2109
                    send_it:
2110
                        /* specific handling for RTP: we use several
2111
                           output stream (one for each RTP
2112
                           connection). XXX: need more abstract handling */
2113
                        if (c->is_packetized) {
2114
                            AVStream *st;
2115
                            /* compute send time and duration */
2116
                            st = c->fmt_in->streams[pkt.stream_index];
2117
                            c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2118
                            if (st->start_time != AV_NOPTS_VALUE)
2119
                                c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2120
                            c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2121
#if 0
2122
                            printf("index=%d pts=%0.3f duration=%0.6f\n",
2123
                                   pkt.stream_index,
2124
                                   (double)c->cur_pts /
2125
                                   AV_TIME_BASE,
2126
                                   (double)c->cur_frame_duration /
2127
                                   AV_TIME_BASE);
2128
#endif
2129
                            /* find RTP context */
2130
                            c->packet_stream_index = pkt.stream_index;
2131
                            ctx = c->rtp_ctx[c->packet_stream_index];
2132
                            if(!ctx) {
2133
                              av_free_packet(&pkt);
2134
                              break;
2135
                            }
2136
                            codec = ctx->streams[0]->codec;
2137
                            /* only one stream per RTP connection */
2138
                            pkt.stream_index = 0;
2139
                        } else {
2140
                            ctx = &c->fmt_ctx;
2141
                            /* Fudge here */
2142
                            codec = ctx->streams[pkt.stream_index]->codec;
2143
                        }
2144

    
2145
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2146
                        if (c->is_packetized) {
2147
                            int max_packet_size;
2148
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2149
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2150
                            else
2151
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2152
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2153
                        } else {
2154
                            ret = url_open_dyn_buf(&ctx->pb);
2155
                        }
2156
                        if (ret < 0) {
2157
                            /* XXX: potential leak */
2158
                            return -1;
2159
                        }
2160
                        if (pkt.dts != AV_NOPTS_VALUE)
2161
                            pkt.dts = av_rescale_q(pkt.dts,
2162
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2163
                                ctx->streams[pkt.stream_index]->time_base);
2164
                        if (pkt.pts != AV_NOPTS_VALUE)
2165
                            pkt.pts = av_rescale_q(pkt.pts,
2166
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2167
                                ctx->streams[pkt.stream_index]->time_base);
2168
                        if (av_write_frame(ctx, &pkt))
2169
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2170

    
2171
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2172
                        c->cur_frame_bytes = len;
2173
                        c->buffer_ptr = c->pb_buffer;
2174
                        c->buffer_end = c->pb_buffer + len;
2175

    
2176
                        codec->frame_number++;
2177
                        if (len == 0)
2178
                            goto redo;
2179
                    }
2180
                    av_free_packet(&pkt);
2181
                }
2182
            }
2183
        }
2184
        break;
2185
    default:
2186
    case HTTPSTATE_SEND_DATA_TRAILER:
2187
        /* last packet test ? */
2188
        if (c->last_packet_sent || c->is_packetized)
2189
            return -1;
2190
        ctx = &c->fmt_ctx;
2191
        /* prepare header */
2192
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2193
            /* XXX: potential leak */
2194
            return -1;
2195
        }
2196
        av_write_trailer(ctx);
2197
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2198
        c->buffer_ptr = c->pb_buffer;
2199
        c->buffer_end = c->pb_buffer + len;
2200

    
2201
        c->last_packet_sent = 1;
2202
        break;
2203
    }
2204
    return 0;
2205
}
2206

    
2207
/* should convert the format at the same time */
2208
/* send data starting at c->buffer_ptr to the output connection
2209
   (either UDP or TCP connection) */
2210
static int http_send_data(HTTPContext *c)
2211
{
2212
    int len, ret;
2213

    
2214
    for(;;) {
2215
        if (c->buffer_ptr >= c->buffer_end) {
2216
            ret = http_prepare_data(c);
2217
            if (ret < 0)
2218
                return -1;
2219
            else if (ret != 0)
2220
                /* state change requested */
2221
                break;
2222
        } else {
2223
            if (c->is_packetized) {
2224
                /* RTP data output */
2225
                len = c->buffer_end - c->buffer_ptr;
2226
                if (len < 4) {
2227
                    /* fail safe - should never happen */
2228
                fail1:
2229
                    c->buffer_ptr = c->buffer_end;
2230
                    return 0;
2231
                }
2232
                len = (c->buffer_ptr[0] << 24) |
2233
                    (c->buffer_ptr[1] << 16) |
2234
                    (c->buffer_ptr[2] << 8) |
2235
                    (c->buffer_ptr[3]);
2236
                if (len > (c->buffer_end - c->buffer_ptr))
2237
                    goto fail1;
2238
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2239
                    /* nothing to send yet: we can wait */
2240
                    return 0;
2241
                }
2242

    
2243
                c->data_count += len;
2244
                update_datarate(&c->datarate, c->data_count);
2245
                if (c->stream)
2246
                    c->stream->bytes_served += len;
2247

    
2248
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2249
                    /* RTP packets are sent inside the RTSP TCP connection */
2250
                    ByteIOContext pb1, *pb = &pb1;
2251
                    int interleaved_index, size;
2252
                    uint8_t header[4];
2253
                    HTTPContext *rtsp_c;
2254

    
2255
                    rtsp_c = c->rtsp_c;
2256
                    /* if no RTSP connection left, error */
2257
                    if (!rtsp_c)
2258
                        return -1;
2259
                    /* if already sending something, then wait. */
2260
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2261
                        break;
2262
                    if (url_open_dyn_buf(pb) < 0)
2263
                        goto fail1;
2264
                    interleaved_index = c->packet_stream_index * 2;
2265
                    /* RTCP packets are sent at odd indexes */
2266
                    if (c->buffer_ptr[1] == 200)
2267
                        interleaved_index++;
2268
                    /* write RTSP TCP header */
2269
                    header[0] = '$';
2270
                    header[1] = interleaved_index;
2271
                    header[2] = len >> 8;
2272
                    header[3] = len;
2273
                    put_buffer(pb, header, 4);
2274
                    /* write RTP packet data */
2275
                    c->buffer_ptr += 4;
2276
                    put_buffer(pb, c->buffer_ptr, len);
2277
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2278
                    /* prepare asynchronous TCP sending */
2279
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2280
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2281
                    c->buffer_ptr += len;
2282

    
2283
                    /* send everything we can NOW */
2284
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2285
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2286
                    if (len > 0)
2287
                        rtsp_c->packet_buffer_ptr += len;
2288
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2289
                        /* if we could not send all the data, we will
2290
                           send it later, so a new state is needed to
2291
                           "lock" the RTSP TCP connection */
2292
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2293
                        break;
2294
                    } else
2295
                        /* all data has been sent */
2296
                        av_freep(&c->packet_buffer);
2297
                } else {
2298
                    /* send RTP packet directly in UDP */
2299
                    c->buffer_ptr += 4;
2300
                    url_write(c->rtp_handles[c->packet_stream_index],
2301
                              c->buffer_ptr, len);
2302
                    c->buffer_ptr += len;
2303
                    /* here we continue as we can send several packets per 10 ms slot */
2304
                }
2305
            } else {
2306
                /* TCP data output */
2307
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2308
                if (len < 0) {
2309
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2310
                        ff_neterrno() != FF_NETERROR(EINTR))
2311
                        /* error : close connection */
2312
                        return -1;
2313
                    else
2314
                        return 0;
2315
                } else
2316
                    c->buffer_ptr += len;
2317

    
2318
                c->data_count += len;
2319
                update_datarate(&c->datarate, c->data_count);
2320
                if (c->stream)
2321
                    c->stream->bytes_served += len;
2322
                break;
2323
            }
2324
        }
2325
    } /* for(;;) */
2326
    return 0;
2327
}
2328

    
2329
static int http_start_receive_data(HTTPContext *c)
2330
{
2331
    int fd;
2332

    
2333
    if (c->stream->feed_opened)
2334
        return -1;
2335

    
2336
    /* Don't permit writing to this one */
2337
    if (c->stream->readonly)
2338
        return -1;
2339

    
2340
    /* open feed */
2341
    fd = open(c->stream->feed_filename, O_RDWR);
2342
    if (fd < 0)
2343
        return -1;
2344
    c->feed_fd = fd;
2345

    
2346
    c->stream->feed_write_index = ffm_read_write_index(fd);
2347
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2348
    lseek(fd, 0, SEEK_SET);
2349

    
2350
    /* init buffer input */
2351
    c->buffer_ptr = c->buffer;
2352
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2353
    c->stream->feed_opened = 1;
2354
    return 0;
2355
}
2356

    
2357
static int http_receive_data(HTTPContext *c)
2358
{
2359
    HTTPContext *c1;
2360

    
2361
    if (c->buffer_end > c->buffer_ptr) {
2362
        int len;
2363

    
2364
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2365
        if (len < 0) {
2366
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2367
                ff_neterrno() != FF_NETERROR(EINTR))
2368
                /* error : close connection */
2369
                goto fail;
2370
        } else if (len == 0)
2371
            /* end of connection : close it */
2372
            goto fail;
2373
        else {
2374
            c->buffer_ptr += len;
2375
            c->data_count += len;
2376
            update_datarate(&c->datarate, c->data_count);
2377
        }
2378
    }
2379

    
2380
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2381
        if (c->buffer[0] != 'f' ||
2382
            c->buffer[1] != 'm') {
2383
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2384
            goto fail;
2385
        }
2386
    }
2387

    
2388
    if (c->buffer_ptr >= c->buffer_end) {
2389
        FFStream *feed = c->stream;
2390
        /* a packet has been received : write it in the store, except
2391
           if header */
2392
        if (c->data_count > FFM_PACKET_SIZE) {
2393

    
2394
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2395
            /* XXX: use llseek or url_seek */
2396
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2397
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2398

    
2399
            feed->feed_write_index += FFM_PACKET_SIZE;
2400
            /* update file size */
2401
            if (feed->feed_write_index > c->stream->feed_size)
2402
                feed->feed_size = feed->feed_write_index;
2403

    
2404
            /* handle wrap around if max file size reached */
2405
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2406
                feed->feed_write_index = FFM_PACKET_SIZE;
2407

    
2408
            /* write index */
2409
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2410

    
2411
            /* wake up any waiting connections */
2412
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2413
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2414
                    c1->stream->feed == c->stream->feed)
2415
                    c1->state = HTTPSTATE_SEND_DATA;
2416
            }
2417
        } else {
2418
            /* We have a header in our hands that contains useful data */
2419
            AVFormatContext s;
2420
            AVInputFormat *fmt_in;
2421
            ByteIOContext *pb = &s.pb;
2422
            int i;
2423

    
2424
            memset(&s, 0, sizeof(s));
2425

    
2426
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2427
            pb->buf_end = c->buffer_end;        /* ?? */
2428
            pb->is_streamed = 1;
2429

    
2430
            /* use feed output format name to find corresponding input format */
2431
            fmt_in = av_find_input_format(feed->fmt->name);
2432
            if (!fmt_in)
2433
                goto fail;
2434

    
2435
            if (fmt_in->priv_data_size > 0) {
2436
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2437
                if (!s.priv_data)
2438
                    goto fail;
2439
            } else
2440
                s.priv_data = NULL;
2441

    
2442
            if (fmt_in->read_header(&s, 0) < 0) {
2443
                av_freep(&s.priv_data);
2444
                goto fail;
2445
            }
2446

    
2447
            /* Now we have the actual streams */
2448
            if (s.nb_streams != feed->nb_streams) {
2449
                av_freep(&s.priv_data);
2450
                goto fail;
2451
            }
2452
            for (i = 0; i < s.nb_streams; i++)
2453
                memcpy(feed->streams[i]->codec,
2454
                       s.streams[i]->codec, sizeof(AVCodecContext));
2455
            av_freep(&s.priv_data);
2456
        }
2457
        c->buffer_ptr = c->buffer;
2458
    }
2459

    
2460
    return 0;
2461
 fail:
2462
    c->stream->feed_opened = 0;
2463
    close(c->feed_fd);
2464
    return -1;
2465
}
2466

    
2467
/********************************************************************/
2468
/* RTSP handling */
2469

    
2470
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2471
{
2472
    const char *str;
2473
    time_t ti;
2474
    char *p;
2475
    char buf2[32];
2476

    
2477
    switch(error_number) {
2478
    case RTSP_STATUS_OK:
2479
        str = "OK";
2480
        break;
2481
    case RTSP_STATUS_METHOD:
2482
        str = "Method Not Allowed";
2483
        break;
2484
    case RTSP_STATUS_BANDWIDTH:
2485
        str = "Not Enough Bandwidth";
2486
        break;
2487
    case RTSP_STATUS_SESSION:
2488
        str = "Session Not Found";
2489
        break;
2490
    case RTSP_STATUS_STATE:
2491
        str = "Method Not Valid in This State";
2492
        break;
2493
    case RTSP_STATUS_AGGREGATE:
2494
        str = "Aggregate operation not allowed";
2495
        break;
2496
    case RTSP_STATUS_ONLY_AGGREGATE:
2497
        str = "Only aggregate operation allowed";
2498
        break;
2499
    case RTSP_STATUS_TRANSPORT:
2500
        str = "Unsupported transport";
2501
        break;
2502
    case RTSP_STATUS_INTERNAL:
2503
        str = "Internal Server Error";
2504
        break;
2505
    case RTSP_STATUS_SERVICE:
2506
        str = "Service Unavailable";
2507
        break;
2508
    case RTSP_STATUS_VERSION:
2509
        str = "RTSP Version not supported";
2510
        break;
2511
    default:
2512
        str = "Unknown Error";
2513
        break;
2514
    }
2515

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

    
2519
    /* output GMT time */
2520
    ti = time(NULL);
2521
    p = ctime(&ti);
2522
    strcpy(buf2, p);
2523
    p = buf2 + strlen(p) - 1;
2524
    if (*p == '\n')
2525
        *p = '\0';
2526
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2527
}
2528

    
2529
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2530
{
2531
    rtsp_reply_header(c, error_number);
2532
    url_fprintf(c->pb, "\r\n");
2533
}
2534

    
2535
static int rtsp_parse_request(HTTPContext *c)
2536
{
2537
    const char *p, *p1, *p2;
2538
    char cmd[32];
2539
    char url[1024];
2540
    char protocol[32];
2541
    char line[1024];
2542
    ByteIOContext pb1;
2543
    int len;
2544
    RTSPHeader header1, *header = &header1;
2545

    
2546
    c->buffer_ptr[0] = '\0';
2547
    p = c->buffer;
2548

    
2549
    get_word(cmd, sizeof(cmd), &p);
2550
    get_word(url, sizeof(url), &p);
2551
    get_word(protocol, sizeof(protocol), &p);
2552

    
2553
    av_strlcpy(c->method, cmd, sizeof(c->method));
2554
    av_strlcpy(c->url, url, sizeof(c->url));
2555
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2556

    
2557
    c->pb = &pb1;
2558
    if (url_open_dyn_buf(c->pb) < 0) {
2559
        /* XXX: cannot do more */
2560
        c->pb = NULL; /* safety */
2561
        return -1;
2562
    }
2563

    
2564
    /* check version name */
2565
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2566
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2567
        goto the_end;
2568
    }
2569

    
2570
    /* parse each header line */
2571
    memset(header, 0, sizeof(RTSPHeader));
2572
    /* skip to next line */
2573
    while (*p != '\n' && *p != '\0')
2574
        p++;
2575
    if (*p == '\n')
2576
        p++;
2577
    while (*p != '\0') {
2578
        p1 = strchr(p, '\n');
2579
        if (!p1)
2580
            break;
2581
        p2 = p1;
2582
        if (p2 > p && p2[-1] == '\r')
2583
            p2--;
2584
        /* skip empty line */
2585
        if (p2 == p)
2586
            break;
2587
        len = p2 - p;
2588
        if (len > sizeof(line) - 1)
2589
            len = sizeof(line) - 1;
2590
        memcpy(line, p, len);
2591
        line[len] = '\0';
2592
        rtsp_parse_line(header, line);
2593
        p = p1 + 1;
2594
    }
2595

    
2596
    /* handle sequence number */
2597
    c->seq = header->seq;
2598

    
2599
    if (!strcmp(cmd, "DESCRIBE"))
2600
        rtsp_cmd_describe(c, url);
2601
    else if (!strcmp(cmd, "OPTIONS"))
2602
        rtsp_cmd_options(c, url);
2603
    else if (!strcmp(cmd, "SETUP"))
2604
        rtsp_cmd_setup(c, url, header);
2605
    else if (!strcmp(cmd, "PLAY"))
2606
        rtsp_cmd_play(c, url, header);
2607
    else if (!strcmp(cmd, "PAUSE"))
2608
        rtsp_cmd_pause(c, url, header);
2609
    else if (!strcmp(cmd, "TEARDOWN"))
2610
        rtsp_cmd_teardown(c, url, header);
2611
    else
2612
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2613

    
2614
 the_end:
2615
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2616
    c->pb = NULL; /* safety */
2617
    if (len < 0) {
2618
        /* XXX: cannot do more */
2619
        return -1;
2620
    }
2621
    c->buffer_ptr = c->pb_buffer;
2622
    c->buffer_end = c->pb_buffer + len;
2623
    c->state = RTSPSTATE_SEND_REPLY;
2624
    return 0;
2625
}
2626

    
2627
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2628
                                   struct in_addr my_ip)
2629
{
2630
    AVFormatContext *avc;
2631
    AVStream avs[MAX_STREAMS];
2632
    int i;
2633

    
2634
    avc =  av_alloc_format_context();
2635
    if (avc == NULL) {
2636
        return -1;
2637
    }
2638
    if (stream->title[0] != 0) {
2639
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2640
    } else {
2641
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2642
    }
2643
    avc->nb_streams = stream->nb_streams;
2644
    if (stream->is_multicast) {
2645
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2646
                 inet_ntoa(stream->multicast_ip),
2647
                 stream->multicast_port, stream->multicast_ttl);
2648
    }
2649

    
2650
    for(i = 0; i < stream->nb_streams; i++) {
2651
        avc->streams[i] = &avs[i];
2652
        avc->streams[i]->codec = stream->streams[i]->codec;
2653
    }
2654
    *pbuffer = av_mallocz(2048);
2655
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2656
    av_free(avc);
2657

    
2658
    return strlen(*pbuffer);
2659
}
2660

    
2661
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2662
{
2663
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2664
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2665
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2666
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2667
    url_fprintf(c->pb, "\r\n");
2668
}
2669

    
2670
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2671
{
2672
    FFStream *stream;
2673
    char path1[1024];
2674
    const char *path;
2675
    uint8_t *content;
2676
    int content_length, len;
2677
    struct sockaddr_in my_addr;
2678

    
2679
    /* find which url is asked */
2680
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2681
    path = path1;
2682
    if (*path == '/')
2683
        path++;
2684

    
2685
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2686
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2687
            !strcmp(path, stream->filename)) {
2688
            goto found;
2689
        }
2690
    }
2691
    /* no stream found */
2692
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2693
    return;
2694

    
2695
 found:
2696
    /* prepare the media description in sdp format */
2697

    
2698
    /* get the host IP */
2699
    len = sizeof(my_addr);
2700
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2701
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2702
    if (content_length < 0) {
2703
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2704
        return;
2705
    }
2706
    rtsp_reply_header(c, RTSP_STATUS_OK);
2707
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2708
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2709
    url_fprintf(c->pb, "\r\n");
2710
    put_buffer(c->pb, content, content_length);
2711
}
2712

    
2713
static HTTPContext *find_rtp_session(const char *session_id)
2714
{
2715
    HTTPContext *c;
2716

    
2717
    if (session_id[0] == '\0')
2718
        return NULL;
2719

    
2720
    for(c = first_http_ctx; c != NULL; c = c->next) {
2721
        if (!strcmp(c->session_id, session_id))
2722
            return c;
2723
    }
2724
    return NULL;
2725
}
2726

    
2727
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2728
{
2729
    RTSPTransportField *th;
2730
    int i;
2731

    
2732
    for(i=0;i<h->nb_transports;i++) {
2733
        th = &h->transports[i];
2734
        if (th->protocol == protocol)
2735
            return th;
2736
    }
2737
    return NULL;
2738
}
2739

    
2740
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2741
                           RTSPHeader *h)
2742
{
2743
    FFStream *stream;
2744
    int stream_index, port;
2745
    char buf[1024];
2746
    char path1[1024];
2747
    const char *path;
2748
    HTTPContext *rtp_c;
2749
    RTSPTransportField *th;
2750
    struct sockaddr_in dest_addr;
2751
    RTSPActionServerSetup setup;
2752

    
2753
    /* find which url is asked */
2754
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2755
    path = path1;
2756
    if (*path == '/')
2757
        path++;
2758

    
2759
    /* now check each stream */
2760
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2761
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2762
            /* accept aggregate filenames only if single stream */
2763
            if (!strcmp(path, stream->filename)) {
2764
                if (stream->nb_streams != 1) {
2765
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2766
                    return;
2767
                }
2768
                stream_index = 0;
2769
                goto found;
2770
            }
2771

    
2772
            for(stream_index = 0; stream_index < stream->nb_streams;
2773
                stream_index++) {
2774
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2775
                         stream->filename, stream_index);
2776
                if (!strcmp(path, buf))
2777
                    goto found;
2778
            }
2779
        }
2780
    }
2781
    /* no stream found */
2782
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2783
    return;
2784
 found:
2785

    
2786
    /* generate session id if needed */
2787
    if (h->session_id[0] == '\0')
2788
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2789
                 av_random(&random_state), av_random(&random_state));
2790

    
2791
    /* find rtp session, and create it if none found */
2792
    rtp_c = find_rtp_session(h->session_id);
2793
    if (!rtp_c) {
2794
        /* always prefer UDP */
2795
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2796
        if (!th) {
2797
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2798
            if (!th) {
2799
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2800
                return;
2801
            }
2802
        }
2803

    
2804
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2805
                                   th->protocol);
2806
        if (!rtp_c) {
2807
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2808
            return;
2809
        }
2810

    
2811
        /* open input stream */
2812
        if (open_input_stream(rtp_c, "") < 0) {
2813
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2814
            return;
2815
        }
2816
    }
2817

    
2818
    /* test if stream is OK (test needed because several SETUP needs
2819
       to be done for a given file) */
2820
    if (rtp_c->stream != stream) {
2821
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2822
        return;
2823
    }
2824

    
2825
    /* test if stream is already set up */
2826
    if (rtp_c->rtp_ctx[stream_index]) {
2827
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2828
        return;
2829
    }
2830

    
2831
    /* check transport */
2832
    th = find_transport(h, rtp_c->rtp_protocol);
2833
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2834
                th->client_port_min <= 0)) {
2835
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2836
        return;
2837
    }
2838

    
2839
    /* setup default options */
2840
    setup.transport_option[0] = '\0';
2841
    dest_addr = rtp_c->from_addr;
2842
    dest_addr.sin_port = htons(th->client_port_min);
2843

    
2844
    /* setup stream */
2845
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2846
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2847
        return;
2848
    }
2849

    
2850
    /* now everything is OK, so we can send the connection parameters */
2851
    rtsp_reply_header(c, RTSP_STATUS_OK);
2852
    /* session ID */
2853
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2854

    
2855
    switch(rtp_c->rtp_protocol) {
2856
    case RTSP_PROTOCOL_RTP_UDP:
2857
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2858
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2859
                    "client_port=%d-%d;server_port=%d-%d",
2860
                    th->client_port_min, th->client_port_min + 1,
2861
                    port, port + 1);
2862
        break;
2863
    case RTSP_PROTOCOL_RTP_TCP:
2864
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2865
                    stream_index * 2, stream_index * 2 + 1);
2866
        break;
2867
    default:
2868
        break;
2869
    }
2870
    if (setup.transport_option[0] != '\0')
2871
        url_fprintf(c->pb, ";%s", setup.transport_option);
2872
    url_fprintf(c->pb, "\r\n");
2873

    
2874

    
2875
    url_fprintf(c->pb, "\r\n");
2876
}
2877

    
2878

    
2879
/* find an rtp connection by using the session ID. Check consistency
2880
   with filename */
2881
static HTTPContext *find_rtp_session_with_url(const char *url,
2882
                                              const char *session_id)
2883
{
2884
    HTTPContext *rtp_c;
2885
    char path1[1024];
2886
    const char *path;
2887
    char buf[1024];
2888
    int s;
2889

    
2890
    rtp_c = find_rtp_session(session_id);
2891
    if (!rtp_c)
2892
        return NULL;
2893

    
2894
    /* find which url is asked */
2895
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2896
    path = path1;
2897
    if (*path == '/')
2898
        path++;
2899
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2900
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2901
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2902
        rtp_c->stream->filename, s);
2903
      if(!strncmp(path, buf, sizeof(buf))) {
2904
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2905
        return rtp_c;
2906
      }
2907
    }
2908
    return NULL;
2909
}
2910

    
2911
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2912
{
2913
    HTTPContext *rtp_c;
2914

    
2915
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2916
    if (!rtp_c) {
2917
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2918
        return;
2919
    }
2920

    
2921
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2922
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2923
        rtp_c->state != HTTPSTATE_READY) {
2924
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2925
        return;
2926
    }
2927

    
2928
#if 0
2929
    /* XXX: seek in stream */
2930
    if (h->range_start != AV_NOPTS_VALUE) {
2931
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2932
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2933
    }
2934
#endif
2935

    
2936
    rtp_c->state = HTTPSTATE_SEND_DATA;
2937

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

    
2945
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2946
{
2947
    HTTPContext *rtp_c;
2948

    
2949
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2950
    if (!rtp_c) {
2951
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2952
        return;
2953
    }
2954

    
2955
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2956
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2957
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2958
        return;
2959
    }
2960

    
2961
    rtp_c->state = HTTPSTATE_READY;
2962
    rtp_c->first_pts = AV_NOPTS_VALUE;
2963
    /* now everything is OK, so we can send the connection parameters */
2964
    rtsp_reply_header(c, RTSP_STATUS_OK);
2965
    /* session ID */
2966
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2967
    url_fprintf(c->pb, "\r\n");
2968
}
2969

    
2970
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2971
{
2972
    HTTPContext *rtp_c;
2973
    char session_id[32];
2974

    
2975
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2976
    if (!rtp_c) {
2977
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2978
        return;
2979
    }
2980

    
2981
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2982

    
2983
    /* abort the session */
2984
    close_connection(rtp_c);
2985

    
2986
    /* now everything is OK, so we can send the connection parameters */
2987
    rtsp_reply_header(c, RTSP_STATUS_OK);
2988
    /* session ID */
2989
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
2990
    url_fprintf(c->pb, "\r\n");
2991
}
2992

    
2993

    
2994
/********************************************************************/
2995
/* RTP handling */
2996

    
2997
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
2998
                                       FFStream *stream, const char *session_id,
2999
                                       enum RTSPProtocol rtp_protocol)
3000
{
3001
    HTTPContext *c = NULL;
3002
    const char *proto_str;
3003

    
3004
    /* XXX: should output a warning page when coming
3005
       close to the connection limit */
3006
    if (nb_connections >= nb_max_connections)
3007
        goto fail;
3008

    
3009
    /* add a new connection */
3010
    c = av_mallocz(sizeof(HTTPContext));
3011
    if (!c)
3012
        goto fail;
3013

    
3014
    c->fd = -1;
3015
    c->poll_entry = NULL;
3016
    c->from_addr = *from_addr;
3017
    c->buffer_size = IOBUFFER_INIT_SIZE;
3018
    c->buffer = av_malloc(c->buffer_size);
3019
    if (!c->buffer)
3020
        goto fail;
3021
    nb_connections++;
3022
    c->stream = stream;
3023
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3024
    c->state = HTTPSTATE_READY;
3025
    c->is_packetized = 1;
3026
    c->rtp_protocol = rtp_protocol;
3027

    
3028
    /* protocol is shown in statistics */
3029
    switch(c->rtp_protocol) {
3030
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3031
        proto_str = "MCAST";
3032
        break;
3033
    case RTSP_PROTOCOL_RTP_UDP:
3034
        proto_str = "UDP";
3035
        break;
3036
    case RTSP_PROTOCOL_RTP_TCP:
3037
        proto_str = "TCP";
3038
        break;
3039
    default:
3040
        proto_str = "???";
3041
        break;
3042
    }
3043
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3044
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3045

    
3046
    current_bandwidth += stream->bandwidth;
3047

    
3048
    c->next = first_http_ctx;
3049
    first_http_ctx = c;
3050
    return c;
3051

    
3052
 fail:
3053
    if (c) {
3054
        av_free(c->buffer);
3055
        av_free(c);
3056
    }
3057
    return NULL;
3058
}
3059

    
3060
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3061
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3062
   used. */
3063
static int rtp_new_av_stream(HTTPContext *c,
3064
                             int stream_index, struct sockaddr_in *dest_addr,
3065
                             HTTPContext *rtsp_c)
3066
{
3067
    AVFormatContext *ctx;
3068
    AVStream *st;
3069
    char *ipaddr;
3070
    URLContext *h;
3071
    uint8_t *dummy_buf;
3072
    char buf2[32];
3073
    int max_packet_size;
3074

    
3075
    /* now we can open the relevant output stream */
3076
    ctx = av_alloc_format_context();
3077
    if (!ctx)
3078
        return -1;
3079
    ctx->oformat = &rtp_muxer;
3080

    
3081
    st = av_mallocz(sizeof(AVStream));
3082
    if (!st)
3083
        goto fail;
3084
    st->codec= avcodec_alloc_context();
3085
    ctx->nb_streams = 1;
3086
    ctx->streams[0] = st;
3087

    
3088
    if (!c->stream->feed ||
3089
        c->stream->feed == c->stream)
3090
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3091
    else
3092
        memcpy(st,
3093
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3094
               sizeof(AVStream));
3095
    st->priv_data = NULL;
3096

    
3097
    /* build destination RTP address */
3098
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3099

    
3100
    switch(c->rtp_protocol) {
3101
    case RTSP_PROTOCOL_RTP_UDP:
3102
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3103
        /* RTP/UDP case */
3104

    
3105
        /* XXX: also pass as parameter to function ? */
3106
        if (c->stream->is_multicast) {
3107
            int ttl;
3108
            ttl = c->stream->multicast_ttl;
3109
            if (!ttl)
3110
                ttl = 16;
3111
            snprintf(ctx->filename, sizeof(ctx->filename),
3112
                     "rtp://%s:%d?multicast=1&ttl=%d",
3113
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3114
        } else {
3115
            snprintf(ctx->filename, sizeof(ctx->filename),
3116
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3117
        }
3118

    
3119
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3120
            goto fail;
3121
        c->rtp_handles[stream_index] = h;
3122
        max_packet_size = url_get_max_packet_size(h);
3123
        break;
3124
    case RTSP_PROTOCOL_RTP_TCP:
3125
        /* RTP/TCP case */
3126
        c->rtsp_c = rtsp_c;
3127
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3128
        break;
3129
    default:
3130
        goto fail;
3131
    }
3132

    
3133
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3134
             ipaddr, ntohs(dest_addr->sin_port),
3135
             ctime1(buf2),
3136
             c->stream->filename, stream_index, c->protocol);
3137

    
3138
    /* normally, no packets should be output here, but the packet size may be checked */
3139
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3140
        /* XXX: close stream */
3141
        goto fail;
3142
    }
3143
    av_set_parameters(ctx, NULL);
3144
    if (av_write_header(ctx) < 0) {
3145
    fail:
3146
        if (h)
3147
            url_close(h);
3148
        av_free(ctx);
3149
        return -1;
3150
    }
3151
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3152
    av_free(dummy_buf);
3153

    
3154
    c->rtp_ctx[stream_index] = ctx;
3155
    return 0;
3156
}
3157

    
3158
/********************************************************************/
3159
/* ffserver initialization */
3160

    
3161
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3162
{
3163
    AVStream *fst;
3164

    
3165
    fst = av_mallocz(sizeof(AVStream));
3166
    if (!fst)
3167
        return NULL;
3168
    fst->codec= avcodec_alloc_context();
3169
    fst->priv_data = av_mallocz(sizeof(FeedData));
3170
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3171
    fst->codec->coded_frame = &dummy_frame;
3172
    fst->index = stream->nb_streams;
3173
    av_set_pts_info(fst, 33, 1, 90000);
3174
    stream->streams[stream->nb_streams++] = fst;
3175
    return fst;
3176
}
3177

    
3178
/* return the stream number in the feed */
3179
static int add_av_stream(FFStream *feed, AVStream *st)
3180
{
3181
    AVStream *fst;
3182
    AVCodecContext *av, *av1;
3183
    int i;
3184

    
3185
    av = st->codec;
3186
    for(i=0;i<feed->nb_streams;i++) {
3187
        st = feed->streams[i];
3188
        av1 = st->codec;
3189
        if (av1->codec_id == av->codec_id &&
3190
            av1->codec_type == av->codec_type &&
3191
            av1->bit_rate == av->bit_rate) {
3192

    
3193
            switch(av->codec_type) {
3194
            case CODEC_TYPE_AUDIO:
3195
                if (av1->channels == av->channels &&
3196
                    av1->sample_rate == av->sample_rate)
3197
                    goto found;
3198
                break;
3199
            case CODEC_TYPE_VIDEO:
3200
                if (av1->width == av->width &&
3201
                    av1->height == av->height &&
3202
                    av1->time_base.den == av->time_base.den &&
3203
                    av1->time_base.num == av->time_base.num &&
3204
                    av1->gop_size == av->gop_size)
3205
                    goto found;
3206
                break;
3207
            default:
3208
                abort();
3209
            }
3210
        }
3211
    }
3212

    
3213
    fst = add_av_stream1(feed, av);
3214
    if (!fst)
3215
        return -1;
3216
    return feed->nb_streams - 1;
3217
 found:
3218
    return i;
3219
}
3220

    
3221
static void remove_stream(FFStream *stream)
3222
{
3223
    FFStream **ps;
3224
    ps = &first_stream;
3225
    while (*ps != NULL) {
3226
        if (*ps == stream)
3227
            *ps = (*ps)->next;
3228
        else
3229
            ps = &(*ps)->next;
3230
    }
3231
}
3232

    
3233
/* specific mpeg4 handling : we extract the raw parameters */
3234
static void extract_mpeg4_header(AVFormatContext *infile)
3235
{
3236
    int mpeg4_count, i, size;
3237
    AVPacket pkt;
3238
    AVStream *st;
3239
    const uint8_t *p;
3240

    
3241
    mpeg4_count = 0;
3242
    for(i=0;i<infile->nb_streams;i++) {
3243
        st = infile->streams[i];
3244
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3245
            st->codec->extradata_size == 0) {
3246
            mpeg4_count++;
3247
        }
3248
    }
3249
    if (!mpeg4_count)
3250
        return;
3251

    
3252
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3253
    while (mpeg4_count > 0) {
3254
        if (av_read_packet(infile, &pkt) < 0)
3255
            break;
3256
        st = infile->streams[pkt.stream_index];
3257
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3258
            st->codec->extradata_size == 0) {
3259
            av_freep(&st->codec->extradata);
3260
            /* fill extradata with the header */
3261
            /* XXX: we make hard suppositions here ! */
3262
            p = pkt.data;
3263
            while (p < pkt.data + pkt.size - 4) {
3264
                /* stop when vop header is found */
3265
                if (p[0] == 0x00 && p[1] == 0x00 &&
3266
                    p[2] == 0x01 && p[3] == 0xb6) {
3267
                    size = p - pkt.data;
3268
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3269
                    st->codec->extradata = av_malloc(size);
3270
                    st->codec->extradata_size = size;
3271
                    memcpy(st->codec->extradata, pkt.data, size);
3272
                    break;
3273
                }
3274
                p++;
3275
            }
3276
            mpeg4_count--;
3277
        }
3278
        av_free_packet(&pkt);
3279
    }
3280
}
3281

    
3282
/* compute the needed AVStream for each file */
3283
static void build_file_streams(void)
3284
{
3285
    FFStream *stream, *stream_next;
3286
    AVFormatContext *infile;
3287
    int i;
3288

    
3289
    /* gather all streams */
3290
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3291
        stream_next = stream->next;
3292
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3293
            !stream->feed) {
3294
            /* the stream comes from a file */
3295
            /* try to open the file */
3296
            /* open stream */
3297
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3298
            if (stream->fmt == &rtp_muxer) {
3299
                /* specific case : if transport stream output to RTP,
3300
                   we use a raw transport stream reader */
3301
                stream->ap_in->mpeg2ts_raw = 1;
3302
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3303
            }
3304

    
3305
            if (av_open_input_file(&infile, stream->feed_filename,
3306
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3307
                http_log("%s not found", stream->feed_filename);
3308
                /* remove stream (no need to spend more time on it) */
3309
            fail:
3310
                remove_stream(stream);
3311
            } else {
3312
                /* find all the AVStreams inside and reference them in
3313
                   'stream' */
3314
                if (av_find_stream_info(infile) < 0) {
3315
                    http_log("Could not find codec parameters from '%s'",
3316
                             stream->feed_filename);
3317
                    av_close_input_file(infile);
3318
                    goto fail;
3319
                }
3320
                extract_mpeg4_header(infile);
3321

    
3322
                for(i=0;i<infile->nb_streams;i++)
3323
                    add_av_stream1(stream, infile->streams[i]->codec);
3324

    
3325
                av_close_input_file(infile);
3326
            }
3327
        }
3328
    }
3329
}
3330

    
3331
/* compute the needed AVStream for each feed */
3332
static void build_feed_streams(void)
3333
{
3334
    FFStream *stream, *feed;
3335
    int i;
3336

    
3337
    /* gather all streams */
3338
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3339
        feed = stream->feed;
3340
        if (feed) {
3341
            if (!stream->is_feed) {
3342
                /* we handle a stream coming from a feed */
3343
                for(i=0;i<stream->nb_streams;i++)
3344
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3345
            }
3346
        }
3347
    }
3348

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

    
3360
    /* create feed files if needed */
3361
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3362
        int fd;
3363

    
3364
        if (url_exist(feed->feed_filename)) {
3365
            /* See if it matches */
3366
            AVFormatContext *s;
3367
            int matches = 0;
3368

    
3369
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3370
                /* Now see if it matches */
3371
                if (s->nb_streams == feed->nb_streams) {
3372
                    matches = 1;
3373
                    for(i=0;i<s->nb_streams;i++) {
3374
                        AVStream *sf, *ss;
3375
                        sf = feed->streams[i];
3376
                        ss = s->streams[i];
3377

    
3378
                        if (sf->index != ss->index ||
3379
                            sf->id != ss->id) {
3380
                            printf("Index & Id do not match for stream %d (%s)\n",
3381
                                   i, feed->feed_filename);
3382
                            matches = 0;
3383
                        } else {
3384
                            AVCodecContext *ccf, *ccs;
3385

    
3386
                            ccf = sf->codec;
3387
                            ccs = ss->codec;
3388
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3389

    
3390
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3391
                                printf("Codecs do not match for stream %d\n", i);
3392
                                matches = 0;
3393
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3394
                                printf("Codec bitrates do not match for stream %d\n", i);
3395
                                matches = 0;
3396
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3397
                                if (CHECK_CODEC(time_base.den) ||
3398
                                    CHECK_CODEC(time_base.num) ||
3399
                                    CHECK_CODEC(width) ||
3400
                                    CHECK_CODEC(height)) {
3401
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3402
                                    matches = 0;
3403
                                }
3404
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3405
                                if (CHECK_CODEC(sample_rate) ||
3406
                                    CHECK_CODEC(channels) ||
3407
                                    CHECK_CODEC(frame_size)) {
3408
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3409
                                    matches = 0;
3410
                                }
3411
                            } else {
3412
                                printf("Unknown codec type\n");
3413
                                matches = 0;
3414
                            }
3415
                        }
3416
                        if (!matches)
3417
                            break;
3418
                    }
3419
                } else
3420
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3421
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3422

    
3423
                av_close_input_file(s);
3424
            } else
3425
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3426
                        feed->feed_filename);
3427

    
3428
            if (!matches) {
3429
                if (feed->readonly) {
3430
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3431
                        feed->feed_filename);
3432
                    exit(1);
3433
                }
3434
                unlink(feed->feed_filename);
3435
            }
3436
        }
3437
        if (!url_exist(feed->feed_filename)) {
3438
            AVFormatContext s1, *s = &s1;
3439

    
3440
            if (feed->readonly) {
3441
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3442
                    feed->feed_filename);
3443
                exit(1);
3444
            }
3445

    
3446
            /* only write the header of the ffm file */
3447
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3448
                fprintf(stderr, "Could not open output feed file '%s'\n",
3449
                        feed->feed_filename);
3450
                exit(1);
3451
            }
3452
            s->oformat = feed->fmt;
3453
            s->nb_streams = feed->nb_streams;
3454
            for(i=0;i<s->nb_streams;i++) {
3455
                AVStream *st;
3456
                st = feed->streams[i];
3457
                s->streams[i] = st;
3458
            }
3459
            av_set_parameters(s, NULL);
3460
            if (av_write_header(s) < 0) {
3461
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3462
                exit(1);
3463
            }
3464
            /* XXX: need better api */
3465
            av_freep(&s->priv_data);
3466
            url_fclose(&s->pb);
3467
        }
3468
        /* get feed size and write index */
3469
        fd = open(feed->feed_filename, O_RDONLY);
3470
        if (fd < 0) {
3471
            fprintf(stderr, "Could not open output feed file '%s'\n",
3472
                    feed->feed_filename);
3473
            exit(1);
3474
        }
3475

    
3476
        feed->feed_write_index = ffm_read_write_index(fd);
3477
        feed->feed_size = lseek(fd, 0, SEEK_END);
3478
        /* ensure that we do not wrap before the end of file */
3479
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3480
            feed->feed_max_size = feed->feed_size;
3481

    
3482
        close(fd);
3483
    }
3484
}
3485

    
3486
/* compute the bandwidth used by each stream */
3487
static void compute_bandwidth(void)
3488
{
3489
    int bandwidth, i;
3490
    FFStream *stream;
3491

    
3492
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3493
        bandwidth = 0;
3494
        for(i=0;i<stream->nb_streams;i++) {
3495
            AVStream *st = stream->streams[i];
3496
            switch(st->codec->codec_type) {
3497
            case CODEC_TYPE_AUDIO:
3498
            case CODEC_TYPE_VIDEO:
3499
                bandwidth += st->codec->bit_rate;
3500
                break;
3501
            default:
3502
                break;
3503
            }
3504
        }
3505
        stream->bandwidth = (bandwidth + 999) / 1000;
3506
    }
3507
}
3508

    
3509
static void get_arg(char *buf, int buf_size, const char **pp)
3510
{
3511
    const char *p;
3512
    char *q;
3513
    int quote;
3514

    
3515
    p = *pp;
3516
    while (isspace(*p)) p++;
3517
    q = buf;
3518
    quote = 0;
3519
    if (*p == '\"' || *p == '\'')
3520
        quote = *p++;
3521
    for(;;) {
3522
        if (quote) {
3523
            if (*p == quote)
3524
                break;
3525
        } else {
3526
            if (isspace(*p))
3527
                break;
3528
        }
3529
        if (*p == '\0')
3530
            break;
3531
        if ((q - buf) < buf_size - 1)
3532
            *q++ = *p;
3533
        p++;
3534
    }
3535
    *q = '\0';
3536
    if (quote && *p == quote)
3537
        p++;
3538
    *pp = p;
3539
}
3540

    
3541
/* add a codec and set the default parameters */
3542
static void add_codec(FFStream *stream, AVCodecContext *av)
3543
{
3544
    AVStream *st;
3545

    
3546
    /* compute default parameters */
3547
    switch(av->codec_type) {
3548
    case CODEC_TYPE_AUDIO:
3549
        if (av->bit_rate == 0)
3550
            av->bit_rate = 64000;
3551
        if (av->sample_rate == 0)
3552
            av->sample_rate = 22050;
3553
        if (av->channels == 0)
3554
            av->channels = 1;
3555
        break;
3556
    case CODEC_TYPE_VIDEO:
3557
        if (av->bit_rate == 0)
3558
            av->bit_rate = 64000;
3559
        if (av->time_base.num == 0){
3560
            av->time_base.den = 5;
3561
            av->time_base.num = 1;
3562
        }
3563
        if (av->width == 0 || av->height == 0) {
3564
            av->width = 160;
3565
            av->height = 128;
3566
        }
3567
        /* Bitrate tolerance is less for streaming */
3568
        if (av->bit_rate_tolerance == 0)
3569
            av->bit_rate_tolerance = av->bit_rate / 4;
3570
        if (av->qmin == 0)
3571
            av->qmin = 3;
3572
        if (av->qmax == 0)
3573
            av->qmax = 31;
3574
        if (av->max_qdiff == 0)
3575
            av->max_qdiff = 3;
3576
        av->qcompress = 0.5;
3577
        av->qblur = 0.5;
3578

    
3579
        if (!av->nsse_weight)
3580
            av->nsse_weight = 8;
3581

    
3582
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3583
        av->me_method = ME_EPZS;
3584
        av->rc_buffer_aggressivity = 1.0;
3585

    
3586
        if (!av->rc_eq)
3587
            av->rc_eq = "tex^qComp";
3588
        if (!av->i_quant_factor)
3589
            av->i_quant_factor = -0.8;
3590
        if (!av->b_quant_factor)
3591
            av->b_quant_factor = 1.25;
3592
        if (!av->b_quant_offset)
3593
            av->b_quant_offset = 1.25;
3594
        if (!av->rc_max_rate)
3595
            av->rc_max_rate = av->bit_rate * 2;
3596

    
3597
        if (av->rc_max_rate && !av->rc_buffer_size) {
3598
            av->rc_buffer_size = av->rc_max_rate;
3599
        }
3600

    
3601

    
3602
        break;
3603
    default:
3604
        abort();
3605
    }
3606

    
3607
    st = av_mallocz(sizeof(AVStream));
3608
    if (!st)
3609
        return;
3610
    st->codec = avcodec_alloc_context();
3611
    stream->streams[stream->nb_streams++] = st;
3612
    memcpy(st->codec, av, sizeof(AVCodecContext));
3613
}
3614

    
3615
static int opt_audio_codec(const char *arg)
3616
{
3617
    AVCodec *p;
3618

    
3619
    p = first_avcodec;
3620
    while (p) {
3621
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3622
            break;
3623
        p = p->next;
3624
    }
3625
    if (p == NULL)
3626
        return CODEC_ID_NONE;
3627

    
3628
    return p->id;
3629
}
3630

    
3631
static int opt_video_codec(const char *arg)
3632
{
3633
    AVCodec *p;
3634

    
3635
    p = first_avcodec;
3636
    while (p) {
3637
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3638
            break;
3639
        p = p->next;
3640
    }
3641
    if (p == NULL)
3642
        return CODEC_ID_NONE;
3643

    
3644
    return p->id;
3645
}
3646

    
3647
/* simplistic plugin support */
3648

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

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

    
3669
    init_func();
3670
}
3671
#endif
3672

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4305
static void show_banner(void)
4306
{
4307
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4308
}
4309

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

    
4322
static void handle_child_exit(int sig)
4323
{
4324
    pid_t pid;
4325
    int status;
4326

    
4327
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4328
        FFStream *feed;
4329

    
4330
        for (feed = first_feed; feed; feed = feed->next) {
4331
            if (feed->pid == pid) {
4332
                int uptime = time(0) - feed->pid_start;
4333

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

    
4337
                if (uptime < 30)
4338
                    /* Turn off any more restarts */
4339
                    feed->child_argv = 0;
4340
            }
4341
        }
4342
    }
4343

    
4344
    need_to_start_children = 1;
4345
}
4346

    
4347
int main(int argc, char **argv)
4348
{
4349
    const char *config_filename;
4350
    int c;
4351
    struct sigaction sigact;
4352

    
4353
    av_register_all();
4354

    
4355
    config_filename = "/etc/ffserver.conf";
4356

    
4357
    my_program_name = argv[0];
4358
    my_program_dir = getcwd(0, 0);
4359
    ffserver_daemon = 1;
4360

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

    
4389
    putenv("http_proxy");               /* Kill the http_proxy */
4390

    
4391
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4392

    
4393
    /* address on which the server will handle HTTP connections */
4394
    my_http_addr.sin_family = AF_INET;
4395
    my_http_addr.sin_port = htons (8080);
4396
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4397

    
4398
    /* address on which the server will handle RTSP connections */
4399
    my_rtsp_addr.sin_family = AF_INET;
4400
    my_rtsp_addr.sin_port = htons (5454);
4401
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4402

    
4403
    nb_max_connections = 5;
4404
    max_bandwidth = 1000;
4405
    first_stream = NULL;
4406
    logfilename[0] = '\0';
4407

    
4408
    memset(&sigact, 0, sizeof(sigact));
4409
    sigact.sa_handler = handle_child_exit;
4410
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4411
    sigaction(SIGCHLD, &sigact, 0);
4412

    
4413
    if (parse_ffconfig(config_filename) < 0) {
4414
        fprintf(stderr, "Incorrect config file - exiting.\n");
4415
        exit(1);
4416
    }
4417

    
4418
    build_file_streams();
4419

    
4420
    build_feed_streams();
4421

    
4422
    compute_bandwidth();
4423

    
4424
    /* put the process in background and detach it from its TTY */
4425
    if (ffserver_daemon) {
4426
        int pid;
4427

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

    
4450
    /* signal init */
4451
    signal(SIGPIPE, SIG_IGN);
4452

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

    
4461
    if (http_server() < 0) {
4462
        fprintf(stderr, "Could not start server\n");
4463
        exit(1);
4464
    }
4465

    
4466
    return 0;
4467
}