Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ d6975eb8

History | View | Annotate | Download (150 KB)

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

    
24
#include <stdarg.h>
25
#include <unistd.h>
26
#include <fcntl.h>
27
#include <sys/ioctl.h>
28
#include <sys/poll.h>
29
#include <errno.h>
30
#include <sys/time.h>
31
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
32
#include <time.h>
33
#include <sys/types.h>
34
#include <sys/socket.h>
35
#include <sys/wait.h>
36
#include <netinet/in.h>
37
#include <arpa/inet.h>
38
#include <netdb.h>
39
#include <signal.h>
40
#ifdef HAVE_DLFCN_H
41
#include <dlfcn.h>
42
#endif
43

    
44
#include "version.h"
45
#include "ffserver.h"
46

    
47
/* maximum number of simultaneous HTTP connections */
48
#define HTTP_MAX_CONNECTIONS 2000
49

    
50
enum HTTPState {
51
    HTTPSTATE_WAIT_REQUEST,
52
    HTTPSTATE_SEND_HEADER,
53
    HTTPSTATE_SEND_DATA_HEADER,
54
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
55
    HTTPSTATE_SEND_DATA_TRAILER,
56
    HTTPSTATE_RECEIVE_DATA,
57
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
58
    HTTPSTATE_READY,
59

    
60
    RTSPSTATE_WAIT_REQUEST,
61
    RTSPSTATE_SEND_REPLY,
62
    RTSPSTATE_SEND_PACKET,
63
};
64

    
65
const char *http_state[] = {
66
    "HTTP_WAIT_REQUEST",
67
    "HTTP_SEND_HEADER",
68

    
69
    "SEND_DATA_HEADER",
70
    "SEND_DATA",
71
    "SEND_DATA_TRAILER",
72
    "RECEIVE_DATA",
73
    "WAIT_FEED",
74
    "READY",
75

    
76
    "RTSP_WAIT_REQUEST",
77
    "RTSP_SEND_REPLY",
78
    "RTSP_SEND_PACKET",
79
};
80

    
81
#define IOBUFFER_INIT_SIZE 8192
82

    
83
/* coef for exponential mean for bitrate estimation in statistics */
84
#define AVG_COEF 0.9
85

    
86
/* timeouts are in ms */
87
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
88
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
89

    
90
#define SYNC_TIMEOUT (10 * 1000)
91

    
92
typedef struct {
93
    int64_t count1, count2;
94
    long time1, time2;
95
} DataRateData;
96

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

    
142
    /* RTSP state specific */
143
    uint8_t *pb_buffer; /* XXX: use that in all the code */
144
    ByteIOContext *pb;
145
    int seq; /* RTSP sequence number */
146

    
147
    /* RTP state specific */
148
    enum RTSPProtocol rtp_protocol;
149
    char session_id[32]; /* session id */
150
    AVFormatContext *rtp_ctx[MAX_STREAMS];
151

    
152
    /* RTP/UDP specific */
153
    URLContext *rtp_handles[MAX_STREAMS];
154

    
155
    /* RTP/TCP specific */
156
    struct HTTPContext *rtsp_c;
157
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
158
} HTTPContext;
159

    
160
static AVFrame dummy_frame;
161

    
162
/* each generated stream is described here */
163
enum StreamType {
164
    STREAM_TYPE_LIVE,
165
    STREAM_TYPE_STATUS,
166
    STREAM_TYPE_REDIRECT,
167
};
168

    
169
enum IPAddressAction {
170
    IP_ALLOW = 1,
171
    IP_DENY,
172
};
173

    
174
typedef struct IPAddressACL {
175
    struct IPAddressACL *next;
176
    enum IPAddressAction action;
177
    /* These are in host order */
178
    struct in_addr first;
179
    struct in_addr last;
180
} IPAddressACL;
181

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

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

    
230
typedef struct FeedData {
231
    long long data_count;
232
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
233
} FeedData;
234

    
235
struct sockaddr_in my_http_addr;
236
struct sockaddr_in my_rtsp_addr;
237

    
238
static char logfilename[1024];
239
static HTTPContext *first_http_ctx;
240
static FFStream *first_feed;   /* contains only feeds */
241
static FFStream *first_stream; /* contains all streams, including feeds */
242

    
243
static void new_connection(int server_fd, int is_rtsp);
244
static void close_connection(HTTPContext *c);
245

    
246
/* HTTP handling */
247
static int handle_connection(HTTPContext *c);
248
static int http_parse_request(HTTPContext *c);
249
static int http_send_data(HTTPContext *c);
250
static void compute_stats(HTTPContext *c);
251
static int open_input_stream(HTTPContext *c, const char *info);
252
static int http_start_receive_data(HTTPContext *c);
253
static int http_receive_data(HTTPContext *c);
254

    
255
/* RTSP handling */
256
static int rtsp_parse_request(HTTPContext *c);
257
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
258
static void rtsp_cmd_options(HTTPContext *c, const char *url);
259
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
260
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
261
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
262
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
263

    
264
/* SDP handling */
265
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
266
                                   struct in_addr my_ip);
267

    
268
/* RTP handling */
269
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
270
                                       FFStream *stream, const char *session_id,
271
                                       enum RTSPProtocol rtp_protocol);
272
static int rtp_new_av_stream(HTTPContext *c,
273
                             int stream_index, struct sockaddr_in *dest_addr,
274
                             HTTPContext *rtsp_c);
275

    
276
static const char *my_program_name;
277
static const char *my_program_dir;
278

    
279
static int ffserver_debug;
280
static int ffserver_daemon;
281
static int no_launch;
282
static int need_to_start_children;
283

    
284
static int nb_max_connections;
285
static int nb_connections;
286

    
287
static int max_bandwidth;
288
static int current_bandwidth;
289

    
290
static long cur_time;           // Making this global saves on passing it around everywhere
291

    
292
static long gettime_ms(void)
293
{
294
    struct timeval tv;
295

    
296
    gettimeofday(&tv,NULL);
297
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
298
}
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 {
347
        if (cur_time - drd->time2 > 5000) {
348
            drd->time1 = drd->time2;
349
            drd->count1 = drd->count2;
350
            drd->time2 = cur_time;
351
            drd->count2 = count;
352
        }
353
    }
354
}
355

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

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

    
365

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

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

    
375
            feed->pid = fork();
376

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

    
387
                for (i = 3; i < 256; i++) {
388
                    close(i);
389
                }
390

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

    
401
                pstrcpy(pathname, sizeof(pathname), my_program_name);
402

    
403
                slash = strrchr(pathname, '/');
404
                if (!slash) {
405
                    slash = pathname;
406
                } else {
407
                    slash++;
408
                }
409
                strcpy(slash, "ffmpeg");
410

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

    
414
                signal(SIGPIPE, SIG_DFL);
415

    
416
                execvp(pathname, feed->child_argv);
417

    
418
                _exit(1);
419
            }
420
        }
421
    }
422
}
423

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

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

    
435
    tmp = 1;
436
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
437

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

    
446
    if (listen (server_fd, 5) < 0) {
447
        perror ("listen");
448
        close(server_fd);
449
        return -1;
450
    }
451
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
452

    
453
    return server_fd;
454
}
455

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

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

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

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

    
482
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
483
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
484
            if (!rtp_c) {
485
                continue;
486
            }
487
            if (open_input_stream(rtp_c, "") < 0) {
488
                fprintf(stderr, "Could not open input stream for stream '%s'\n",
489
                        stream->filename);
490
                continue;
491
            }
492

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

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

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

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

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

    
526
    http_log("ffserver started.\n");
527

    
528
    start_children(first_feed);
529

    
530
    first_http_ctx = NULL;
531
    nb_connections = 0;
532

    
533
    start_multicast();
534

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

    
541
        poll_entry->fd = rtsp_server_fd;
542
        poll_entry->events = POLLIN;
543
        poll_entry++;
544

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

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

    
603
        cur_time = gettime_ms();
604

    
605
        if (need_to_start_children) {
606
            need_to_start_children = 0;
607
            start_children(first_feed);
608
        }
609

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

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

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

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

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

    
654
    len = sizeof(from_addr);
655
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
656
                &len);
657
    if (fd < 0)
658
        return;
659
    fcntl(fd, F_SETFL, O_NONBLOCK);
660

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

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

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

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

    
683
    start_wait_request(c, is_rtsp);
684

    
685
    return;
686

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

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

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

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

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

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

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

    
751
    ctx = &c->fmt_ctx;
752

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

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

    
766
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
767
        current_bandwidth -= c->stream->bandwidth;
768
    av_freep(&c->pb_buffer);
769
    av_freep(&c->packet_buffer);
770
    av_free(c->buffer);
771
    av_free(c);
772
    nb_connections--;
773
}
774

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

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

    
788
        /* no need to read if no events */
789
        if (!(c->poll_entry->revents & POLLIN))
790
            return 0;
791
        /* read the data */
792
    read_loop:
793
        len = read(c->fd, c->buffer_ptr, 1);
794
        if (len < 0) {
795
            if (errno != EAGAIN && errno != 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 = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
829
        if (len < 0) {
830
            if (errno != EAGAIN && errno != EINTR) {
831
                /* error : close connection */
832
                av_freep(&c->pb_buffer);
833
                return -1;
834
            }
835
        } else {
836
            c->buffer_ptr += len;
837
            if (c->stream)
838
                c->stream->bytes_served += len;
839
            c->data_count += len;
840
            if (c->buffer_ptr >= c->buffer_end) {
841
                av_freep(&c->pb_buffer);
842
                /* if error, exit */
843
                if (c->http_error) {
844
                    return -1;
845
                }
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
        break;
870
    case HTTPSTATE_RECEIVE_DATA:
871
        /* no need to read if no events */
872
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
873
            return -1;
874
        if (!(c->poll_entry->revents & POLLIN))
875
            return 0;
876
        if (http_receive_data(c) < 0)
877
            return -1;
878
        break;
879
    case HTTPSTATE_WAIT_FEED:
880
        /* no need to read if no events */
881
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
882
            return -1;
883

    
884
        /* nothing to do, we'll be waken up by incoming feed packets */
885
        break;
886

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

    
946
static int extract_rates(char *rates, int ratelen, const char *request)
947
{
948
    const char *p;
949

    
950
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
951
        if (strncasecmp(p, "Pragma:", 7) == 0) {
952
            const char *q = p + 7;
953

    
954
            while (*q && *q != '\n' && isspace(*q))
955
                q++;
956

    
957
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
958
                int stream_no;
959
                int rate_no;
960

    
961
                q += 20;
962

    
963
                memset(rates, 0xff, ratelen);
964

    
965
                while (1) {
966
                    while (*q && *q != '\n' && *q != ':')
967
                        q++;
968

    
969
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
970
                        break;
971
                    }
972
                    stream_no--;
973
                    if (stream_no < ratelen && stream_no >= 0) {
974
                        rates[stream_no] = rate_no;
975
                    }
976

    
977
                    while (*q && *q != '\n' && !isspace(*q))
978
                        q++;
979
                }
980

    
981
                return 1;
982
            }
983
        }
984
        p = strchr(p, '\n');
985
        if (!p)
986
            break;
987

    
988
        p++;
989
    }
990

    
991
    return 0;
992
}
993

    
994
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
995
{
996
    int i;
997
    int best_bitrate = 100000000;
998
    int best = -1;
999

    
1000
    for (i = 0; i < feed->nb_streams; i++) {
1001
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1002

    
1003
        if (feed_codec->codec_id != codec->codec_id ||
1004
            feed_codec->sample_rate != codec->sample_rate ||
1005
            feed_codec->width != codec->width ||
1006
            feed_codec->height != codec->height) {
1007
            continue;
1008
        }
1009

    
1010
        /* Potential stream */
1011

    
1012
        /* We want the fastest stream less than bit_rate, or the slowest
1013
         * faster than bit_rate
1014
         */
1015

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

    
1029
    return best;
1030
}
1031

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

    
1038
    /* Not much we can do for a feed */
1039
    if (!req->feed)
1040
        return 0;
1041

    
1042
    for (i = 0; i < req->nb_streams; i++) {
1043
        AVCodecContext *codec = req->streams[i]->codec;
1044

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

    
1063
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1064
            action_required = 1;
1065
    }
1066

    
1067
    return action_required;
1068
}
1069

    
1070

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

    
1078
        /* Now update the stream */
1079
    }
1080
    c->switch_feed_streams[i] = -1;
1081
}
1082

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

    
1094
static void get_word(char *buf, int buf_size, const char **pp)
1095
{
1096
    const char *p;
1097
    char *q;
1098

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

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

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

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

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

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

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

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

    
1181
    p = c->buffer;
1182
    get_word(cmd, sizeof(cmd), (const char **)&p);
1183
    pstrcpy(c->method, sizeof(c->method), cmd);
1184

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

    
1192
    get_word(url, sizeof(url), (const char **)&p);
1193
    pstrcpy(c->url, sizeof(c->url), url);
1194

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

    
1199
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1200

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

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

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

    
1228
        p++;
1229
    }
1230

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

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

    
1261
    c->stream = stream;
1262
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1263
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1264

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

    
1276
        /* prepare output buffer */
1277
        c->buffer_ptr = c->buffer;
1278
        c->buffer_end = q;
1279
        c->state = HTTPSTATE_SEND_HEADER;
1280
        return 0;
1281
    }
1282

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

    
1293
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1294
        current_bandwidth += stream->bandwidth;
1295
    }
1296

    
1297
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1298
        c->http_error = 200;
1299
        q = c->buffer;
1300
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1301
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1302
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1303
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1304
        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");
1305
        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",
1306
            current_bandwidth, max_bandwidth);
1307
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1308

    
1309
        /* prepare output buffer */
1310
        c->buffer_ptr = c->buffer;
1311
        c->buffer_end = q;
1312
        c->state = HTTPSTATE_SEND_HEADER;
1313
        return 0;
1314
    }
1315

    
1316
    if (redir_type != REDIR_NONE) {
1317
        char *hostinfo = 0;
1318

    
1319
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1320
            if (strncasecmp(p, "Host:", 5) == 0) {
1321
                hostinfo = p + 5;
1322
                break;
1323
            }
1324
            p = strchr(p, '\n');
1325
            if (!p)
1326
                break;
1327

    
1328
            p++;
1329
        }
1330

    
1331
        if (hostinfo) {
1332
            char *eoh;
1333
            char hostbuf[260];
1334

    
1335
            while (isspace(*hostinfo))
1336
                hostinfo++;
1337

    
1338
            eoh = strchr(hostinfo, '\n');
1339
            if (eoh) {
1340
                if (eoh[-1] == '\r')
1341
                    eoh--;
1342

    
1343
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1344
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1345
                    hostbuf[eoh - hostinfo] = 0;
1346

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

    
1399
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1400
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1401
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1402

    
1403
                            len = sizeof(my_addr);
1404
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1405

    
1406
                            /* XXX: should use a dynamic buffer */
1407
                            sdp_data_size = prepare_sdp_description(stream,
1408
                                                                    &sdp_data,
1409
                                                                    my_addr.sin_addr);
1410
                            if (sdp_data_size > 0) {
1411
                                memcpy(q, sdp_data, sdp_data_size);
1412
                                q += sdp_data_size;
1413
                                *q = '\0';
1414
                                av_free(sdp_data);
1415
                            }
1416
                        }
1417
                        break;
1418
                    default:
1419
                        av_abort();
1420
                        break;
1421
                    }
1422

    
1423
                    /* prepare output buffer */
1424
                    c->buffer_ptr = c->buffer;
1425
                    c->buffer_end = q;
1426
                    c->state = HTTPSTATE_SEND_HEADER;
1427
                    return 0;
1428
                }
1429
            }
1430
        }
1431

    
1432
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1433
        goto send_error;
1434
    }
1435

    
1436
    stream->conns_served++;
1437

    
1438
    /* XXX: add there authenticate and IP match */
1439

    
1440
    if (c->post) {
1441
        /* if post, it means a feed is being sent */
1442
        if (!stream->is_feed) {
1443
            /* However it might be a status report from WMP! Lets log the data
1444
             * as it might come in handy one day
1445
             */
1446
            char *logline = 0;
1447
            int client_id = 0;
1448

    
1449
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1450
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1451
                    logline = p;
1452
                    break;
1453
                }
1454
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1455
                    client_id = strtol(p + 18, 0, 10);
1456
                }
1457
                p = strchr(p, '\n');
1458
                if (!p)
1459
                    break;
1460

    
1461
                p++;
1462
            }
1463

    
1464
            if (logline) {
1465
                char *eol = strchr(logline, '\n');
1466

    
1467
                logline += 17;
1468

    
1469
                if (eol) {
1470
                    if (eol[-1] == '\r')
1471
                        eol--;
1472
                    http_log("%.*s\n", (int) (eol - logline), logline);
1473
                    c->suppress_log = 1;
1474
                }
1475
            }
1476

    
1477
#ifdef DEBUG_WMP
1478
            http_log("\nGot request:\n%s\n", c->buffer);
1479
#endif
1480

    
1481
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1482
                HTTPContext *wmpc;
1483

    
1484
                /* Now we have to find the client_id */
1485
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1486
                    if (wmpc->wmp_client_id == client_id)
1487
                        break;
1488
                }
1489

    
1490
                if (wmpc) {
1491
                    if (modify_current_stream(wmpc, ratebuf)) {
1492
                        wmpc->switch_pending = 1;
1493
                    }
1494
                }
1495
            }
1496

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

    
1510
#ifdef DEBUG_WMP
1511
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1512
        http_log("\nGot request:\n%s\n", c->buffer);
1513
    }
1514
#endif
1515

    
1516
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1517
        goto send_stats;
1518

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

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

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

    
1537
        c->wmp_client_id = random() & 0x7fffffff;
1538

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

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

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

    
1574
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1575
{
1576
    static const char *suffix = " kMGTP";
1577
    const char *s;
1578

    
1579
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1580
    }
1581

    
1582
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1583
}
1584

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

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

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

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

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

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

    
1658
                    for(i=0;i<stream->nb_streams;i++) {
1659
                        AVStream *st = stream->streams[i];
1660
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1661
                        switch(st->codec->codec_type) {
1662
                        case CODEC_TYPE_AUDIO:
1663
                            audio_bit_rate += st->codec->bit_rate;
1664
                            if (codec) {
1665
                                if (*audio_codec_name)
1666
                                    audio_codec_name_extra = "...";
1667
                                audio_codec_name = codec->name;
1668
                            }
1669
                            break;
1670
                        case CODEC_TYPE_VIDEO:
1671
                            video_bit_rate += st->codec->bit_rate;
1672
                            if (codec) {
1673
                                if (*video_codec_name)
1674
                                    video_codec_name_extra = "...";
1675
                                video_codec_name = codec->name;
1676
                            }
1677
                            break;
1678
                        case CODEC_TYPE_DATA:
1679
                            video_bit_rate += st->codec->bit_rate;
1680
                            break;
1681
                        default:
1682
                            av_abort();
1683
                        }
1684
                    }
1685
                    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",
1686
                                 stream->fmt->name,
1687
                                 stream->bandwidth,
1688
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1689
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1690
                    if (stream->feed) {
1691
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1692
                    } else {
1693
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1694
                    }
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
                    break;
1755
                case CODEC_TYPE_VIDEO:
1756
                    type = "video";
1757
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1758
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1759
                    break;
1760
                default:
1761
                    av_abort();
1762
                }
1763
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1764
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1765
            }
1766
            url_fprintf(pb, "</table>\n");
1767

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1913
#if 0
1914
    { time_t when = stream_pos / 1000000;
1915
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1916
    }
1917
#endif
1918

    
1919
    /* open stream */
1920
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1921
                           buf_size, c->stream->ap_in) < 0) {
1922
        http_log("%s not found", input_filename);
1923
        return -1;
1924
    }
1925
    c->fmt_in = s;
1926

    
1927
    /* open each parser */
1928
    for(i=0;i<s->nb_streams;i++)
1929
        open_parser(s, i);
1930

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

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

    
1952
/* return the server clock (in us) */
1953
static int64_t get_server_clock(HTTPContext *c)
1954
{
1955
    /* compute current pts value from system time */
1956
    return (int64_t)(cur_time - c->start_time) * 1000LL;
1957
}
1958

    
1959
/* return the estimated time at which the current packet must be sent
1960
   (in us) */
1961
static int64_t get_packet_send_clock(HTTPContext *c)
1962
{
1963
    int bytes_left, bytes_sent, frame_bytes;
1964

    
1965
    frame_bytes = c->cur_frame_bytes;
1966
    if (frame_bytes <= 0) {
1967
        return c->cur_pts;
1968
    } else {
1969
        bytes_left = c->buffer_end - c->buffer_ptr;
1970
        bytes_sent = frame_bytes - bytes_left;
1971
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1972
    }
1973
}
1974

    
1975

    
1976
static int http_prepare_data(HTTPContext *c)
1977
{
1978
    int i, len, ret;
1979
    AVFormatContext *ctx;
1980

    
1981
    av_freep(&c->pb_buffer);
1982
    switch(c->state) {
1983
    case HTTPSTATE_SEND_DATA_HEADER:
1984
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1985
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
1986
                c->stream->author);
1987
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
1988
                c->stream->comment);
1989
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
1990
                c->stream->copyright);
1991
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
1992
                c->stream->title);
1993

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

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

    
2021
        /* prepare header and save header data in a stream */
2022
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2023
            /* XXX: potential leak */
2024
            return -1;
2025
        }
2026
        c->fmt_ctx.pb.is_streamed = 1;
2027

    
2028
        av_set_parameters(&c->fmt_ctx, NULL);
2029
        av_write_header(&c->fmt_ctx);
2030

    
2031
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2032
        c->buffer_ptr = c->pb_buffer;
2033
        c->buffer_end = c->pb_buffer + len;
2034

    
2035
        c->state = HTTPSTATE_SEND_DATA;
2036
        c->last_packet_sent = 0;
2037
        break;
2038
    case HTTPSTATE_SEND_DATA:
2039
        /* find a new packet */
2040
        {
2041
            AVPacket pkt;
2042

    
2043
            /* read a packet from the input stream */
2044
            if (c->stream->feed) {
2045
                ffm_set_write_index(c->fmt_in,
2046
                                    c->stream->feed->feed_write_index,
2047
                                    c->stream->feed->feed_size);
2048
            }
2049

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

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

    
2155
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2156
                        if (c->is_packetized) {
2157
                            int max_packet_size;
2158
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2159
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2160
                            else
2161
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2162
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2163
                        } else {
2164
                            ret = url_open_dyn_buf(&ctx->pb);
2165
                        }
2166
                        if (ret < 0) {
2167
                            /* XXX: potential leak */
2168
                            return -1;
2169
                        }
2170
                        if (av_write_frame(ctx, &pkt)) {
2171
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2172
                        }
2173

    
2174
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2175
                        c->cur_frame_bytes = len;
2176
                        c->buffer_ptr = c->pb_buffer;
2177
                        c->buffer_end = c->pb_buffer + len;
2178

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

    
2204
        c->last_packet_sent = 1;
2205
        break;
2206
    }
2207
    return 0;
2208
}
2209

    
2210
/* in bit/s */
2211
#define SHORT_TERM_BANDWIDTH 8000000
2212

    
2213
/* should convert the format at the same time */
2214
/* send data starting at c->buffer_ptr to the output connection
2215
   (either UDP or TCP connection) */
2216
static int http_send_data(HTTPContext *c)
2217
{
2218
    int len, ret;
2219

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

    
2250
                c->data_count += len;
2251
                update_datarate(&c->datarate, c->data_count);
2252
                if (c->stream)
2253
                    c->stream->bytes_served += len;
2254

    
2255
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2256
                    /* RTP packets are sent inside the RTSP TCP connection */
2257
                    ByteIOContext pb1, *pb = &pb1;
2258
                    int interleaved_index, size;
2259
                    uint8_t header[4];
2260
                    HTTPContext *rtsp_c;
2261

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

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

    
2339
static int http_start_receive_data(HTTPContext *c)
2340
{
2341
    int fd;
2342

    
2343
    if (c->stream->feed_opened)
2344
        return -1;
2345

    
2346
    /* Don't permit writing to this one */
2347
    if (c->stream->readonly)
2348
        return -1;
2349

    
2350
    /* open feed */
2351
    fd = open(c->stream->feed_filename, O_RDWR);
2352
    if (fd < 0)
2353
        return -1;
2354
    c->feed_fd = fd;
2355

    
2356
    c->stream->feed_write_index = ffm_read_write_index(fd);
2357
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2358
    lseek(fd, 0, SEEK_SET);
2359

    
2360
    /* init buffer input */
2361
    c->buffer_ptr = c->buffer;
2362
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2363
    c->stream->feed_opened = 1;
2364
    return 0;
2365
}
2366

    
2367
static int http_receive_data(HTTPContext *c)
2368
{
2369
    HTTPContext *c1;
2370

    
2371
    if (c->buffer_end > c->buffer_ptr) {
2372
        int len;
2373

    
2374
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2375
        if (len < 0) {
2376
            if (errno != EAGAIN && errno != EINTR) {
2377
                /* error : close connection */
2378
                goto fail;
2379
            }
2380
        } else if (len == 0) {
2381
            /* end of connection : close it */
2382
            goto fail;
2383
        } else {
2384
            c->buffer_ptr += len;
2385
            c->data_count += len;
2386
            update_datarate(&c->datarate, c->data_count);
2387
        }
2388
    }
2389

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

    
2398
    if (c->buffer_ptr >= c->buffer_end) {
2399
        FFStream *feed = c->stream;
2400
        /* a packet has been received : write it in the store, except
2401
           if header */
2402
        if (c->data_count > FFM_PACKET_SIZE) {
2403

    
2404
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2405
            /* XXX: use llseek or url_seek */
2406
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2407
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2408

    
2409
            feed->feed_write_index += FFM_PACKET_SIZE;
2410
            /* update file size */
2411
            if (feed->feed_write_index > c->stream->feed_size)
2412
                feed->feed_size = feed->feed_write_index;
2413

    
2414
            /* handle wrap around if max file size reached */
2415
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2416
                feed->feed_write_index = FFM_PACKET_SIZE;
2417

    
2418
            /* write index */
2419
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2420

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

    
2435
            memset(&s, 0, sizeof(s));
2436

    
2437
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2438
            pb->buf_end = c->buffer_end;        /* ?? */
2439
            pb->is_streamed = 1;
2440

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

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

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

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

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

    
2479
/********************************************************************/
2480
/* RTSP handling */
2481

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

    
2489
    switch(error_number) {
2490
#define DEF(n, c, s) case c: str = s; break;
2491
#include "rtspcodes.h"
2492
#undef DEF
2493
    default:
2494
        str = "Unknown Error";
2495
        break;
2496
    }
2497

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

    
2501
    /* output GMT time */
2502
    ti = time(NULL);
2503
    p = ctime(&ti);
2504
    strcpy(buf2, p);
2505
    p = buf2 + strlen(p) - 1;
2506
    if (*p == '\n')
2507
        *p = '\0';
2508
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2509
}
2510

    
2511
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2512
{
2513
    rtsp_reply_header(c, error_number);
2514
    url_fprintf(c->pb, "\r\n");
2515
}
2516

    
2517
static int rtsp_parse_request(HTTPContext *c)
2518
{
2519
    const char *p, *p1, *p2;
2520
    char cmd[32];
2521
    char url[1024];
2522
    char protocol[32];
2523
    char line[1024];
2524
    ByteIOContext pb1;
2525
    int len;
2526
    RTSPHeader header1, *header = &header1;
2527

    
2528
    c->buffer_ptr[0] = '\0';
2529
    p = c->buffer;
2530

    
2531
    get_word(cmd, sizeof(cmd), &p);
2532
    get_word(url, sizeof(url), &p);
2533
    get_word(protocol, sizeof(protocol), &p);
2534

    
2535
    pstrcpy(c->method, sizeof(c->method), cmd);
2536
    pstrcpy(c->url, sizeof(c->url), url);
2537
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2538

    
2539
    c->pb = &pb1;
2540
    if (url_open_dyn_buf(c->pb) < 0) {
2541
        /* XXX: cannot do more */
2542
        c->pb = NULL; /* safety */
2543
        return -1;
2544
    }
2545

    
2546
    /* check version name */
2547
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2548
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2549
        goto the_end;
2550
    }
2551

    
2552
    /* parse each header line */
2553
    memset(header, 0, sizeof(RTSPHeader));
2554
    /* skip to next line */
2555
    while (*p != '\n' && *p != '\0')
2556
        p++;
2557
    if (*p == '\n')
2558
        p++;
2559
    while (*p != '\0') {
2560
        p1 = strchr(p, '\n');
2561
        if (!p1)
2562
            break;
2563
        p2 = p1;
2564
        if (p2 > p && p2[-1] == '\r')
2565
            p2--;
2566
        /* skip empty line */
2567
        if (p2 == p)
2568
            break;
2569
        len = p2 - p;
2570
        if (len > sizeof(line) - 1)
2571
            len = sizeof(line) - 1;
2572
        memcpy(line, p, len);
2573
        line[len] = '\0';
2574
        rtsp_parse_line(header, line);
2575
        p = p1 + 1;
2576
    }
2577

    
2578
    /* handle sequence number */
2579
    c->seq = header->seq;
2580

    
2581
    if (!strcmp(cmd, "DESCRIBE")) {
2582
        rtsp_cmd_describe(c, url);
2583
    } else if (!strcmp(cmd, "OPTIONS")) {
2584
        rtsp_cmd_options(c, url);
2585
    } else if (!strcmp(cmd, "SETUP")) {
2586
        rtsp_cmd_setup(c, url, header);
2587
    } else if (!strcmp(cmd, "PLAY")) {
2588
        rtsp_cmd_play(c, url, header);
2589
    } else if (!strcmp(cmd, "PAUSE")) {
2590
        rtsp_cmd_pause(c, url, header);
2591
    } else if (!strcmp(cmd, "TEARDOWN")) {
2592
        rtsp_cmd_teardown(c, url, header);
2593
    } else {
2594
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2595
    }
2596
 the_end:
2597
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2598
    c->pb = NULL; /* safety */
2599
    if (len < 0) {
2600
        /* XXX: cannot do more */
2601
        return -1;
2602
    }
2603
    c->buffer_ptr = c->pb_buffer;
2604
    c->buffer_end = c->pb_buffer + len;
2605
    c->state = RTSPSTATE_SEND_REPLY;
2606
    return 0;
2607
}
2608

    
2609
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2610
   AVFormatContext */
2611
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2612
                                   struct in_addr my_ip)
2613
{
2614
    ByteIOContext pb1, *pb = &pb1;
2615
    int i, payload_type, port, private_payload_type, j;
2616
    const char *ipstr, *title, *mediatype;
2617
    AVStream *st;
2618

    
2619
    if (url_open_dyn_buf(pb) < 0)
2620
        return -1;
2621

    
2622
    /* general media info */
2623

    
2624
    url_fprintf(pb, "v=0\n");
2625
    ipstr = inet_ntoa(my_ip);
2626
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2627
    title = stream->title;
2628
    if (title[0] == '\0')
2629
        title = "No Title";
2630
    url_fprintf(pb, "s=%s\n", title);
2631
    if (stream->comment[0] != '\0')
2632
        url_fprintf(pb, "i=%s\n", stream->comment);
2633
    if (stream->is_multicast) {
2634
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2635
    }
2636
    /* for each stream, we output the necessary info */
2637
    private_payload_type = RTP_PT_PRIVATE;
2638
    for(i = 0; i < stream->nb_streams; i++) {
2639
        st = stream->streams[i];
2640
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2641
            mediatype = "video";
2642
        } else {
2643
            switch(st->codec->codec_type) {
2644
            case CODEC_TYPE_AUDIO:
2645
                mediatype = "audio";
2646
                break;
2647
            case CODEC_TYPE_VIDEO:
2648
                mediatype = "video";
2649
                break;
2650
            default:
2651
                mediatype = "application";
2652
                break;
2653
            }
2654
        }
2655
        /* NOTE: the port indication is not correct in case of
2656
           unicast. It is not an issue because RTSP gives it */
2657
        payload_type = rtp_get_payload_type(st->codec);
2658
        if (payload_type < 0)
2659
            payload_type = private_payload_type++;
2660
        if (stream->is_multicast) {
2661
            port = stream->multicast_port + 2 * i;
2662
        } else {
2663
            port = 0;
2664
        }
2665
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2666
                    mediatype, port, payload_type);
2667
        if (payload_type >= RTP_PT_PRIVATE) {
2668
            /* for private payload type, we need to give more info */
2669
            switch(st->codec->codec_id) {
2670
            case CODEC_ID_MPEG4:
2671
                {
2672
                    uint8_t *data;
2673
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2674
                                payload_type, 90000);
2675
                    /* we must also add the mpeg4 header */
2676
                    data = st->codec->extradata;
2677
                    if (data) {
2678
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2679
                        for(j=0;j<st->codec->extradata_size;j++) {
2680
                            url_fprintf(pb, "%02x", data[j]);
2681
                        }
2682
                        url_fprintf(pb, "\n");
2683
                    }
2684
                }
2685
                break;
2686
            default:
2687
                /* XXX: add other codecs ? */
2688
                goto fail;
2689
            }
2690
        }
2691
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2692
    }
2693
    return url_close_dyn_buf(pb, pbuffer);
2694
 fail:
2695
    url_close_dyn_buf(pb, pbuffer);
2696
    av_free(*pbuffer);
2697
    return -1;
2698
}
2699

    
2700
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2701
{
2702
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2703
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2704
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2705
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2706
    url_fprintf(c->pb, "\r\n");
2707
}
2708

    
2709
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2710
{
2711
    FFStream *stream;
2712
    char path1[1024];
2713
    const char *path;
2714
    uint8_t *content;
2715
    int content_length, len;
2716
    struct sockaddr_in my_addr;
2717

    
2718
    /* find which url is asked */
2719
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2720
    path = path1;
2721
    if (*path == '/')
2722
        path++;
2723

    
2724
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2725
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2726
            !strcmp(path, stream->filename)) {
2727
            goto found;
2728
        }
2729
    }
2730
    /* no stream found */
2731
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2732
    return;
2733

    
2734
 found:
2735
    /* prepare the media description in sdp format */
2736

    
2737
    /* get the host IP */
2738
    len = sizeof(my_addr);
2739
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2740
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2741
    if (content_length < 0) {
2742
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2743
        return;
2744
    }
2745
    rtsp_reply_header(c, RTSP_STATUS_OK);
2746
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2747
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2748
    url_fprintf(c->pb, "\r\n");
2749
    put_buffer(c->pb, content, content_length);
2750
}
2751

    
2752
static HTTPContext *find_rtp_session(const char *session_id)
2753
{
2754
    HTTPContext *c;
2755

    
2756
    if (session_id[0] == '\0')
2757
        return NULL;
2758

    
2759
    for(c = first_http_ctx; c != NULL; c = c->next) {
2760
        if (!strcmp(c->session_id, session_id))
2761
            return c;
2762
    }
2763
    return NULL;
2764
}
2765

    
2766
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2767
{
2768
    RTSPTransportField *th;
2769
    int i;
2770

    
2771
    for(i=0;i<h->nb_transports;i++) {
2772
        th = &h->transports[i];
2773
        if (th->protocol == protocol)
2774
            return th;
2775
    }
2776
    return NULL;
2777
}
2778

    
2779
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2780
                           RTSPHeader *h)
2781
{
2782
    FFStream *stream;
2783
    int stream_index, port;
2784
    char buf[1024];
2785
    char path1[1024];
2786
    const char *path;
2787
    HTTPContext *rtp_c;
2788
    RTSPTransportField *th;
2789
    struct sockaddr_in dest_addr;
2790
    RTSPActionServerSetup setup;
2791

    
2792
    /* find which url is asked */
2793
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2794
    path = path1;
2795
    if (*path == '/')
2796
        path++;
2797

    
2798
    /* now check each stream */
2799
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2800
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2801
            /* accept aggregate filenames only if single stream */
2802
            if (!strcmp(path, stream->filename)) {
2803
                if (stream->nb_streams != 1) {
2804
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2805
                    return;
2806
                }
2807
                stream_index = 0;
2808
                goto found;
2809
            }
2810

    
2811
            for(stream_index = 0; stream_index < stream->nb_streams;
2812
                stream_index++) {
2813
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2814
                         stream->filename, stream_index);
2815
                if (!strcmp(path, buf))
2816
                    goto found;
2817
            }
2818
        }
2819
    }
2820
    /* no stream found */
2821
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2822
    return;
2823
 found:
2824

    
2825
    /* generate session id if needed */
2826
    if (h->session_id[0] == '\0') {
2827
        snprintf(h->session_id, sizeof(h->session_id),
2828
                 "%08x%08x", (int)random(), (int)random());
2829
    }
2830

    
2831
    /* find rtp session, and create it if none found */
2832
    rtp_c = find_rtp_session(h->session_id);
2833
    if (!rtp_c) {
2834
        /* always prefer UDP */
2835
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2836
        if (!th) {
2837
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2838
            if (!th) {
2839
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2840
                return;
2841
            }
2842
        }
2843

    
2844
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2845
                                   th->protocol);
2846
        if (!rtp_c) {
2847
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2848
            return;
2849
        }
2850

    
2851
        /* open input stream */
2852
        if (open_input_stream(rtp_c, "") < 0) {
2853
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2854
            return;
2855
        }
2856
    }
2857

    
2858
    /* test if stream is OK (test needed because several SETUP needs
2859
       to be done for a given file) */
2860
    if (rtp_c->stream != stream) {
2861
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2862
        return;
2863
    }
2864

    
2865
    /* test if stream is already set up */
2866
    if (rtp_c->rtp_ctx[stream_index]) {
2867
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2868
        return;
2869
    }
2870

    
2871
    /* check transport */
2872
    th = find_transport(h, rtp_c->rtp_protocol);
2873
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2874
                th->client_port_min <= 0)) {
2875
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2876
        return;
2877
    }
2878

    
2879
    /* setup default options */
2880
    setup.transport_option[0] = '\0';
2881
    dest_addr = rtp_c->from_addr;
2882
    dest_addr.sin_port = htons(th->client_port_min);
2883

    
2884
    /* add transport option if needed */
2885
    if (ff_rtsp_callback) {
2886
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2887
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2888
                             (char *)&setup, sizeof(setup),
2889
                             stream->rtsp_option) < 0) {
2890
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2891
            return;
2892
        }
2893
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2894
    }
2895

    
2896
    /* setup stream */
2897
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2898
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2899
        return;
2900
    }
2901

    
2902
    /* now everything is OK, so we can send the connection parameters */
2903
    rtsp_reply_header(c, RTSP_STATUS_OK);
2904
    /* session ID */
2905
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2906

    
2907
    switch(rtp_c->rtp_protocol) {
2908
    case RTSP_PROTOCOL_RTP_UDP:
2909
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2910
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2911
                    "client_port=%d-%d;server_port=%d-%d",
2912
                    th->client_port_min, th->client_port_min + 1,
2913
                    port, port + 1);
2914
        break;
2915
    case RTSP_PROTOCOL_RTP_TCP:
2916
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2917
                    stream_index * 2, stream_index * 2 + 1);
2918
        break;
2919
    default:
2920
        break;
2921
    }
2922
    if (setup.transport_option[0] != '\0') {
2923
        url_fprintf(c->pb, ";%s", setup.transport_option);
2924
    }
2925
    url_fprintf(c->pb, "\r\n");
2926

    
2927

    
2928
    url_fprintf(c->pb, "\r\n");
2929
}
2930

    
2931

    
2932
/* find an rtp connection by using the session ID. Check consistency
2933
   with filename */
2934
static HTTPContext *find_rtp_session_with_url(const char *url,
2935
                                              const char *session_id)
2936
{
2937
    HTTPContext *rtp_c;
2938
    char path1[1024];
2939
    const char *path;
2940
    char buf[1024];
2941
    int s;
2942

    
2943
    rtp_c = find_rtp_session(session_id);
2944
    if (!rtp_c)
2945
        return NULL;
2946

    
2947
    /* find which url is asked */
2948
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2949
    path = path1;
2950
    if (*path == '/')
2951
        path++;
2952
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2953
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2954
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2955
        rtp_c->stream->filename, s);
2956
      if(!strncmp(path, buf, sizeof(buf))) {
2957
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2958
        return rtp_c;
2959
      }
2960
    }
2961
    return NULL;
2962
}
2963

    
2964
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2965
{
2966
    HTTPContext *rtp_c;
2967

    
2968
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2969
    if (!rtp_c) {
2970
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2971
        return;
2972
    }
2973

    
2974
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2975
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2976
        rtp_c->state != HTTPSTATE_READY) {
2977
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2978
        return;
2979
    }
2980

    
2981
#if 0
2982
    /* XXX: seek in stream */
2983
    if (h->range_start != AV_NOPTS_VALUE) {
2984
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2985
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2986
    }
2987
#endif
2988

    
2989
    rtp_c->state = HTTPSTATE_SEND_DATA;
2990

    
2991
    /* now everything is OK, so we can send the connection parameters */
2992
    rtsp_reply_header(c, RTSP_STATUS_OK);
2993
    /* session ID */
2994
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2995
    url_fprintf(c->pb, "\r\n");
2996
}
2997

    
2998
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2999
{
3000
    HTTPContext *rtp_c;
3001

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

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

    
3014
    rtp_c->state = HTTPSTATE_READY;
3015
    rtp_c->first_pts = AV_NOPTS_VALUE;
3016
    /* now everything is OK, so we can send the connection parameters */
3017
    rtsp_reply_header(c, RTSP_STATUS_OK);
3018
    /* session ID */
3019
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3020
    url_fprintf(c->pb, "\r\n");
3021
}
3022

    
3023
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3024
{
3025
    HTTPContext *rtp_c;
3026

    
3027
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3028
    if (!rtp_c) {
3029
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3030
        return;
3031
    }
3032

    
3033
    /* abort the session */
3034
    close_connection(rtp_c);
3035

    
3036
    if (ff_rtsp_callback) {
3037
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3038
                         NULL, 0,
3039
                         rtp_c->stream->rtsp_option);
3040
    }
3041

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

    
3049

    
3050
/********************************************************************/
3051
/* RTP handling */
3052

    
3053
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3054
                                       FFStream *stream, const char *session_id,
3055
                                       enum RTSPProtocol rtp_protocol)
3056
{
3057
    HTTPContext *c = NULL;
3058
    const char *proto_str;
3059

    
3060
    /* XXX: should output a warning page when coming
3061
       close to the connection limit */
3062
    if (nb_connections >= nb_max_connections)
3063
        goto fail;
3064

    
3065
    /* add a new connection */
3066
    c = av_mallocz(sizeof(HTTPContext));
3067
    if (!c)
3068
        goto fail;
3069

    
3070
    c->fd = -1;
3071
    c->poll_entry = NULL;
3072
    c->from_addr = *from_addr;
3073
    c->buffer_size = IOBUFFER_INIT_SIZE;
3074
    c->buffer = av_malloc(c->buffer_size);
3075
    if (!c->buffer)
3076
        goto fail;
3077
    nb_connections++;
3078
    c->stream = stream;
3079
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3080
    c->state = HTTPSTATE_READY;
3081
    c->is_packetized = 1;
3082
    c->rtp_protocol = rtp_protocol;
3083

    
3084
    /* protocol is shown in statistics */
3085
    switch(c->rtp_protocol) {
3086
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3087
        proto_str = "MCAST";
3088
        break;
3089
    case RTSP_PROTOCOL_RTP_UDP:
3090
        proto_str = "UDP";
3091
        break;
3092
    case RTSP_PROTOCOL_RTP_TCP:
3093
        proto_str = "TCP";
3094
        break;
3095
    default:
3096
        proto_str = "???";
3097
        break;
3098
    }
3099
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3100
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3101

    
3102
    current_bandwidth += stream->bandwidth;
3103

    
3104
    c->next = first_http_ctx;
3105
    first_http_ctx = c;
3106
    return c;
3107

    
3108
 fail:
3109
    if (c) {
3110
        av_free(c->buffer);
3111
        av_free(c);
3112
    }
3113
    return NULL;
3114
}
3115

    
3116
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3117
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3118
   used. */
3119
static int rtp_new_av_stream(HTTPContext *c,
3120
                             int stream_index, struct sockaddr_in *dest_addr,
3121
                             HTTPContext *rtsp_c)
3122
{
3123
    AVFormatContext *ctx;
3124
    AVStream *st;
3125
    char *ipaddr;
3126
    URLContext *h;
3127
    uint8_t *dummy_buf;
3128
    char buf2[32];
3129
    int max_packet_size;
3130

    
3131
    /* now we can open the relevant output stream */
3132
    ctx = av_alloc_format_context();
3133
    if (!ctx)
3134
        return -1;
3135
    ctx->oformat = &rtp_muxer;
3136

    
3137
    st = av_mallocz(sizeof(AVStream));
3138
    if (!st)
3139
        goto fail;
3140
    st->codec= avcodec_alloc_context();
3141
    ctx->nb_streams = 1;
3142
    ctx->streams[0] = st;
3143

    
3144
    if (!c->stream->feed ||
3145
        c->stream->feed == c->stream) {
3146
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3147
    } else {
3148
        memcpy(st,
3149
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3150
               sizeof(AVStream));
3151
    }
3152

    
3153
    /* build destination RTP address */
3154
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3155

    
3156
    switch(c->rtp_protocol) {
3157
    case RTSP_PROTOCOL_RTP_UDP:
3158
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3159
        /* RTP/UDP case */
3160

    
3161
        /* XXX: also pass as parameter to function ? */
3162
        if (c->stream->is_multicast) {
3163
            int ttl;
3164
            ttl = c->stream->multicast_ttl;
3165
            if (!ttl)
3166
                ttl = 16;
3167
            snprintf(ctx->filename, sizeof(ctx->filename),
3168
                     "rtp://%s:%d?multicast=1&ttl=%d",
3169
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3170
        } else {
3171
            snprintf(ctx->filename, sizeof(ctx->filename),
3172
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3173
        }
3174

    
3175
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3176
            goto fail;
3177
        c->rtp_handles[stream_index] = h;
3178
        max_packet_size = url_get_max_packet_size(h);
3179
        break;
3180
    case RTSP_PROTOCOL_RTP_TCP:
3181
        /* RTP/TCP case */
3182
        c->rtsp_c = rtsp_c;
3183
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3184
        break;
3185
    default:
3186
        goto fail;
3187
    }
3188

    
3189
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3190
             ipaddr, ntohs(dest_addr->sin_port),
3191
             ctime1(buf2),
3192
             c->stream->filename, stream_index, c->protocol);
3193

    
3194
    /* normally, no packets should be output here, but the packet size may be checked */
3195
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3196
        /* XXX: close stream */
3197
        goto fail;
3198
    }
3199
    av_set_parameters(ctx, NULL);
3200
    if (av_write_header(ctx) < 0) {
3201
    fail:
3202
        if (h)
3203
            url_close(h);
3204
        av_free(ctx);
3205
        return -1;
3206
    }
3207
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3208
    av_free(dummy_buf);
3209

    
3210
    c->rtp_ctx[stream_index] = ctx;
3211
    return 0;
3212
}
3213

    
3214
/********************************************************************/
3215
/* ffserver initialization */
3216

    
3217
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3218
{
3219
    AVStream *fst;
3220

    
3221
    fst = av_mallocz(sizeof(AVStream));
3222
    if (!fst)
3223
        return NULL;
3224
    fst->codec= avcodec_alloc_context();
3225
    fst->priv_data = av_mallocz(sizeof(FeedData));
3226
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3227
    fst->codec->coded_frame = &dummy_frame;
3228
    fst->index = stream->nb_streams;
3229
    av_set_pts_info(fst, 33, 1, 90000);
3230
    stream->streams[stream->nb_streams++] = fst;
3231
    return fst;
3232
}
3233

    
3234
/* return the stream number in the feed */
3235
static int add_av_stream(FFStream *feed, AVStream *st)
3236
{
3237
    AVStream *fst;
3238
    AVCodecContext *av, *av1;
3239
    int i;
3240

    
3241
    av = st->codec;
3242
    for(i=0;i<feed->nb_streams;i++) {
3243
        st = feed->streams[i];
3244
        av1 = st->codec;
3245
        if (av1->codec_id == av->codec_id &&
3246
            av1->codec_type == av->codec_type &&
3247
            av1->bit_rate == av->bit_rate) {
3248

    
3249
            switch(av->codec_type) {
3250
            case CODEC_TYPE_AUDIO:
3251
                if (av1->channels == av->channels &&
3252
                    av1->sample_rate == av->sample_rate)
3253
                    goto found;
3254
                break;
3255
            case CODEC_TYPE_VIDEO:
3256
                if (av1->width == av->width &&
3257
                    av1->height == av->height &&
3258
                    av1->time_base.den == av->time_base.den &&
3259
                    av1->time_base.num == av->time_base.num &&
3260
                    av1->gop_size == av->gop_size)
3261
                    goto found;
3262
                break;
3263
            default:
3264
                av_abort();
3265
            }
3266
        }
3267
    }
3268

    
3269
    fst = add_av_stream1(feed, av);
3270
    if (!fst)
3271
        return -1;
3272
    return feed->nb_streams - 1;
3273
 found:
3274
    return i;
3275
}
3276

    
3277
static void remove_stream(FFStream *stream)
3278
{
3279
    FFStream **ps;
3280
    ps = &first_stream;
3281
    while (*ps != NULL) {
3282
        if (*ps == stream) {
3283
            *ps = (*ps)->next;
3284
        } else {
3285
            ps = &(*ps)->next;
3286
        }
3287
    }
3288
}
3289

    
3290
/* specific mpeg4 handling : we extract the raw parameters */
3291
static void extract_mpeg4_header(AVFormatContext *infile)
3292
{
3293
    int mpeg4_count, i, size;
3294
    AVPacket pkt;
3295
    AVStream *st;
3296
    const uint8_t *p;
3297

    
3298
    mpeg4_count = 0;
3299
    for(i=0;i<infile->nb_streams;i++) {
3300
        st = infile->streams[i];
3301
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3302
            st->codec->extradata_size == 0) {
3303
            mpeg4_count++;
3304
        }
3305
    }
3306
    if (!mpeg4_count)
3307
        return;
3308

    
3309
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3310
    while (mpeg4_count > 0) {
3311
        if (av_read_packet(infile, &pkt) < 0)
3312
            break;
3313
        st = infile->streams[pkt.stream_index];
3314
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3315
            st->codec->extradata_size == 0) {
3316
            av_freep(&st->codec->extradata);
3317
            /* fill extradata with the header */
3318
            /* XXX: we make hard suppositions here ! */
3319
            p = pkt.data;
3320
            while (p < pkt.data + pkt.size - 4) {
3321
                /* stop when vop header is found */
3322
                if (p[0] == 0x00 && p[1] == 0x00 &&
3323
                    p[2] == 0x01 && p[3] == 0xb6) {
3324
                    size = p - pkt.data;
3325
                    //                    av_hex_dump(pkt.data, size);
3326
                    st->codec->extradata = av_malloc(size);
3327
                    st->codec->extradata_size = size;
3328
                    memcpy(st->codec->extradata, pkt.data, size);
3329
                    break;
3330
                }
3331
                p++;
3332
            }
3333
            mpeg4_count--;
3334
        }
3335
        av_free_packet(&pkt);
3336
    }
3337
}
3338

    
3339
/* compute the needed AVStream for each file */
3340
static void build_file_streams(void)
3341
{
3342
    FFStream *stream, *stream_next;
3343
    AVFormatContext *infile;
3344
    int i;
3345

    
3346
    /* gather all streams */
3347
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3348
        stream_next = stream->next;
3349
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3350
            !stream->feed) {
3351
            /* the stream comes from a file */
3352
            /* try to open the file */
3353
            /* open stream */
3354
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3355
            if (stream->fmt == &rtp_muxer) {
3356
                /* specific case : if transport stream output to RTP,
3357
                   we use a raw transport stream reader */
3358
                stream->ap_in->mpeg2ts_raw = 1;
3359
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3360
            }
3361

    
3362
            if (av_open_input_file(&infile, stream->feed_filename,
3363
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3364
                http_log("%s not found", stream->feed_filename);
3365
                /* remove stream (no need to spend more time on it) */
3366
            fail:
3367
                remove_stream(stream);
3368
            } else {
3369
                /* find all the AVStreams inside and reference them in
3370
                   'stream' */
3371
                if (av_find_stream_info(infile) < 0) {
3372
                    http_log("Could not find codec parameters from '%s'",
3373
                             stream->feed_filename);
3374
                    av_close_input_file(infile);
3375
                    goto fail;
3376
                }
3377
                extract_mpeg4_header(infile);
3378

    
3379
                for(i=0;i<infile->nb_streams;i++) {
3380
                    add_av_stream1(stream, infile->streams[i]->codec);
3381
                }
3382
                av_close_input_file(infile);
3383
            }
3384
        }
3385
    }
3386
}
3387

    
3388
/* compute the needed AVStream for each feed */
3389
static void build_feed_streams(void)
3390
{
3391
    FFStream *stream, *feed;
3392
    int i;
3393

    
3394
    /* gather all streams */
3395
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3396
        feed = stream->feed;
3397
        if (feed) {
3398
            if (!stream->is_feed) {
3399
                /* we handle a stream coming from a feed */
3400
                for(i=0;i<stream->nb_streams;i++) {
3401
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3402
                }
3403
            }
3404
        }
3405
    }
3406

    
3407
    /* gather all streams */
3408
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3409
        feed = stream->feed;
3410
        if (feed) {
3411
            if (stream->is_feed) {
3412
                for(i=0;i<stream->nb_streams;i++) {
3413
                    stream->feed_streams[i] = i;
3414
                }
3415
            }
3416
        }
3417
    }
3418

    
3419
    /* create feed files if needed */
3420
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3421
        int fd;
3422

    
3423
        if (url_exist(feed->feed_filename)) {
3424
            /* See if it matches */
3425
            AVFormatContext *s;
3426
            int matches = 0;
3427

    
3428
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3429
                /* Now see if it matches */
3430
                if (s->nb_streams == feed->nb_streams) {
3431
                    matches = 1;
3432
                    for(i=0;i<s->nb_streams;i++) {
3433
                        AVStream *sf, *ss;
3434
                        sf = feed->streams[i];
3435
                        ss = s->streams[i];
3436

    
3437
                        if (sf->index != ss->index ||
3438
                            sf->id != ss->id) {
3439
                            printf("Index & Id do not match for stream %d (%s)\n",
3440
                                   i, feed->feed_filename);
3441
                            matches = 0;
3442
                        } else {
3443
                            AVCodecContext *ccf, *ccs;
3444

    
3445
                            ccf = sf->codec;
3446
                            ccs = ss->codec;
3447
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3448

    
3449
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3450
                                printf("Codecs do not match for stream %d\n", i);
3451
                                matches = 0;
3452
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3453
                                printf("Codec bitrates do not match for stream %d\n", i);
3454
                                matches = 0;
3455
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3456
                                if (CHECK_CODEC(time_base.den) ||
3457
                                    CHECK_CODEC(time_base.num) ||
3458
                                    CHECK_CODEC(width) ||
3459
                                    CHECK_CODEC(height)) {
3460
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3461
                                    matches = 0;
3462
                                }
3463
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3464
                                if (CHECK_CODEC(sample_rate) ||
3465
                                    CHECK_CODEC(channels) ||
3466
                                    CHECK_CODEC(frame_size)) {
3467
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3468
                                    matches = 0;
3469
                                }
3470
                            } else {
3471
                                printf("Unknown codec type\n");
3472
                                matches = 0;
3473
                            }
3474
                        }
3475
                        if (!matches) {
3476
                            break;
3477
                        }
3478
                    }
3479
                } else {
3480
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3481
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3482
                }
3483

    
3484
                av_close_input_file(s);
3485
            } else {
3486
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3487
                        feed->feed_filename);
3488
            }
3489
            if (!matches) {
3490
                if (feed->readonly) {
3491
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3492
                        feed->feed_filename);
3493
                    exit(1);
3494
                }
3495
                unlink(feed->feed_filename);
3496
            }
3497
        }
3498
        if (!url_exist(feed->feed_filename)) {
3499
            AVFormatContext s1, *s = &s1;
3500

    
3501
            if (feed->readonly) {
3502
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3503
                    feed->feed_filename);
3504
                exit(1);
3505
            }
3506

    
3507
            /* only write the header of the ffm file */
3508
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3509
                fprintf(stderr, "Could not open output feed file '%s'\n",
3510
                        feed->feed_filename);
3511
                exit(1);
3512
            }
3513
            s->oformat = feed->fmt;
3514
            s->nb_streams = feed->nb_streams;
3515
            for(i=0;i<s->nb_streams;i++) {
3516
                AVStream *st;
3517
                st = feed->streams[i];
3518
                s->streams[i] = st;
3519
            }
3520
            av_set_parameters(s, NULL);
3521
            av_write_header(s);
3522
            /* XXX: need better api */
3523
            av_freep(&s->priv_data);
3524
            url_fclose(&s->pb);
3525
        }
3526
        /* get feed size and write index */
3527
        fd = open(feed->feed_filename, O_RDONLY);
3528
        if (fd < 0) {
3529
            fprintf(stderr, "Could not open output feed file '%s'\n",
3530
                    feed->feed_filename);
3531
            exit(1);
3532
        }
3533

    
3534
        feed->feed_write_index = ffm_read_write_index(fd);
3535
        feed->feed_size = lseek(fd, 0, SEEK_END);
3536
        /* ensure that we do not wrap before the end of file */
3537
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3538
            feed->feed_max_size = feed->feed_size;
3539

    
3540
        close(fd);
3541
    }
3542
}
3543

    
3544
/* compute the bandwidth used by each stream */
3545
static void compute_bandwidth(void)
3546
{
3547
    int bandwidth, i;
3548
    FFStream *stream;
3549

    
3550
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3551
        bandwidth = 0;
3552
        for(i=0;i<stream->nb_streams;i++) {
3553
            AVStream *st = stream->streams[i];
3554
            switch(st->codec->codec_type) {
3555
            case CODEC_TYPE_AUDIO:
3556
            case CODEC_TYPE_VIDEO:
3557
                bandwidth += st->codec->bit_rate;
3558
                break;
3559
            default:
3560
                break;
3561
            }
3562
        }
3563
        stream->bandwidth = (bandwidth + 999) / 1000;
3564
    }
3565
}
3566

    
3567
static void get_arg(char *buf, int buf_size, const char **pp)
3568
{
3569
    const char *p;
3570
    char *q;
3571
    int quote;
3572

    
3573
    p = *pp;
3574
    while (isspace(*p)) p++;
3575
    q = buf;
3576
    quote = 0;
3577
    if (*p == '\"' || *p == '\'')
3578
        quote = *p++;
3579
    for(;;) {
3580
        if (quote) {
3581
            if (*p == quote)
3582
                break;
3583
        } else {
3584
            if (isspace(*p))
3585
                break;
3586
        }
3587
        if (*p == '\0')
3588
            break;
3589
        if ((q - buf) < buf_size - 1)
3590
            *q++ = *p;
3591
        p++;
3592
    }
3593
    *q = '\0';
3594
    if (quote && *p == quote)
3595
        p++;
3596
    *pp = p;
3597
}
3598

    
3599
/* add a codec and set the default parameters */
3600
static void add_codec(FFStream *stream, AVCodecContext *av)
3601
{
3602
    AVStream *st;
3603

    
3604
    /* compute default parameters */
3605
    switch(av->codec_type) {
3606
    case CODEC_TYPE_AUDIO:
3607
        if (av->bit_rate == 0)
3608
            av->bit_rate = 64000;
3609
        if (av->sample_rate == 0)
3610
            av->sample_rate = 22050;
3611
        if (av->channels == 0)
3612
            av->channels = 1;
3613
        break;
3614
    case CODEC_TYPE_VIDEO:
3615
        if (av->bit_rate == 0)
3616
            av->bit_rate = 64000;
3617
        if (av->time_base.num == 0){
3618
            av->time_base.den = 5;
3619
            av->time_base.num = 1;
3620
        }
3621
        if (av->width == 0 || av->height == 0) {
3622
            av->width = 160;
3623
            av->height = 128;
3624
        }
3625
        /* Bitrate tolerance is less for streaming */
3626
        if (av->bit_rate_tolerance == 0)
3627
            av->bit_rate_tolerance = av->bit_rate / 4;
3628
        if (av->qmin == 0)
3629
            av->qmin = 3;
3630
        if (av->qmax == 0)
3631
            av->qmax = 31;
3632
        if (av->max_qdiff == 0)
3633
            av->max_qdiff = 3;
3634
        av->qcompress = 0.5;
3635
        av->qblur = 0.5;
3636

    
3637
        if (!av->nsse_weight)
3638
            av->nsse_weight = 8;
3639

    
3640
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3641
        av->me_method = ME_EPZS;
3642
        av->rc_buffer_aggressivity = 1.0;
3643

    
3644
        if (!av->rc_eq)
3645
            av->rc_eq = "tex^qComp";
3646
        if (!av->i_quant_factor)
3647
            av->i_quant_factor = -0.8;
3648
        if (!av->b_quant_factor)
3649
            av->b_quant_factor = 1.25;
3650
        if (!av->b_quant_offset)
3651
            av->b_quant_offset = 1.25;
3652
        if (!av->rc_max_rate)
3653
            av->rc_max_rate = av->bit_rate * 2;
3654

    
3655
        if (av->rc_max_rate && !av->rc_buffer_size) {
3656
            av->rc_buffer_size = av->rc_max_rate;
3657
        }
3658

    
3659

    
3660
        break;
3661
    default:
3662
        av_abort();
3663
    }
3664

    
3665
    st = av_mallocz(sizeof(AVStream));
3666
    if (!st)
3667
        return;
3668
    st->codec = avcodec_alloc_context();
3669
    stream->streams[stream->nb_streams++] = st;
3670
    memcpy(st->codec, av, sizeof(AVCodecContext));
3671
}
3672

    
3673
static int opt_audio_codec(const char *arg)
3674
{
3675
    AVCodec *p;
3676

    
3677
    p = first_avcodec;
3678
    while (p) {
3679
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3680
            break;
3681
        p = p->next;
3682
    }
3683
    if (p == NULL) {
3684
        return CODEC_ID_NONE;
3685
    }
3686

    
3687
    return p->id;
3688
}
3689

    
3690
static int opt_video_codec(const char *arg)
3691
{
3692
    AVCodec *p;
3693

    
3694
    p = first_avcodec;
3695
    while (p) {
3696
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3697
            break;
3698
        p = p->next;
3699
    }
3700
    if (p == NULL) {
3701
        return CODEC_ID_NONE;
3702
    }
3703

    
3704
    return p->id;
3705
}
3706

    
3707
/* simplistic plugin support */
3708

    
3709
#ifdef HAVE_DLOPEN
3710
static void load_module(const char *filename)
3711
{
3712
    void *dll;
3713
    void (*init_func)(void);
3714
    dll = dlopen(filename, RTLD_NOW);
3715
    if (!dll) {
3716
        fprintf(stderr, "Could not load module '%s' - %s\n",
3717
                filename, dlerror());
3718
        return;
3719
    }
3720

    
3721
    init_func = dlsym(dll, "ffserver_module_init");
3722
    if (!init_func) {
3723
        fprintf(stderr,
3724
                "%s: init function 'ffserver_module_init()' not found\n",
3725
                filename);
3726
        dlclose(dll);
3727
    }
3728

    
3729
    init_func();
3730
}
3731
#endif
3732

    
3733
static int parse_ffconfig(const char *filename)
3734
{
3735
    FILE *f;
3736
    char line[1024];
3737
    char cmd[64];
3738
    char arg[1024];
3739
    const char *p;
3740
    int val, errors, line_num;
3741
    FFStream **last_stream, *stream, *redirect;
3742
    FFStream **last_feed, *feed;
3743
    AVCodecContext audio_enc, video_enc;
3744
    int audio_id, video_id;
3745

    
3746
    f = fopen(filename, "r");
3747
    if (!f) {
3748
        perror(filename);
3749
        return -1;
3750
    }
3751

    
3752
    errors = 0;
3753
    line_num = 0;
3754
    first_stream = NULL;
3755
    last_stream = &first_stream;
3756
    first_feed = NULL;
3757
    last_feed = &first_feed;
3758
    stream = NULL;
3759
    feed = NULL;
3760
    redirect = NULL;
3761
    audio_id = CODEC_ID_NONE;
3762
    video_id = CODEC_ID_NONE;
3763
    for(;;) {
3764
        if (fgets(line, sizeof(line), f) == NULL)
3765
            break;
3766
        line_num++;
3767
        p = line;
3768
        while (isspace(*p))
3769
            p++;
3770
        if (*p == '\0' || *p == '#')
3771
            continue;
3772

    
3773
        get_arg(cmd, sizeof(cmd), &p);
3774

    
3775
        if (!strcasecmp(cmd, "Port")) {
3776
            get_arg(arg, sizeof(arg), &p);
3777
            my_http_addr.sin_port = htons (atoi(arg));
3778
        } else if (!strcasecmp(cmd, "BindAddress")) {
3779
            get_arg(arg, sizeof(arg), &p);
3780
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3781
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3782
                        filename, line_num, arg);
3783
                errors++;
3784
            }
3785
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3786
            ffserver_daemon = 0;
3787
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3788
            get_arg(arg, sizeof(arg), &p);
3789
            my_rtsp_addr.sin_port = htons (atoi(arg));
3790
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3791
            get_arg(arg, sizeof(arg), &p);
3792
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3793
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3794
                        filename, line_num, arg);
3795
                errors++;
3796
            }
3797
        } else if (!strcasecmp(cmd, "MaxClients")) {
3798
            get_arg(arg, sizeof(arg), &p);
3799
            val = atoi(arg);
3800
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3801
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3802
                        filename, line_num, arg);
3803
                errors++;
3804
            } else {
3805
                nb_max_connections = val;
3806
            }
3807
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3808
            get_arg(arg, sizeof(arg), &p);
3809
            val = atoi(arg);
3810
            if (val < 10 || val > 100000) {
3811
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3812
                        filename, line_num, arg);
3813
                errors++;
3814
            } else {
3815
                max_bandwidth = val;
3816
            }
3817
        } else if (!strcasecmp(cmd, "CustomLog")) {
3818
            get_arg(logfilename, sizeof(logfilename), &p);
3819
        } else if (!strcasecmp(cmd, "<Feed")) {
3820
            /*********************************************/
3821
            /* Feed related options */
3822
            char *q;
3823
            if (stream || feed) {
3824
                fprintf(stderr, "%s:%d: Already in a tag\n",
3825
                        filename, line_num);
3826
            } else {
3827
                feed = av_mallocz(sizeof(FFStream));
3828
                /* add in stream list */
3829
                *last_stream = feed;
3830
                last_stream = &feed->next;
3831
                /* add in feed list */
3832
                *last_feed = feed;
3833
                last_feed = &feed->next_feed;
3834

    
3835
                get_arg(feed->filename, sizeof(feed->filename), &p);
3836
                q = strrchr(feed->filename, '>');
3837
                if (*q)
3838
                    *q = '\0';
3839
                feed->fmt = guess_format("ffm", NULL, NULL);
3840
                /* defaut feed file */
3841
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3842
                         "/tmp/%s.ffm", feed->filename);
3843
                feed->feed_max_size = 5 * 1024 * 1024;
3844
                feed->is_feed = 1;
3845
                feed->feed = feed; /* self feeding :-) */
3846
            }
3847
        } else if (!strcasecmp(cmd, "Launch")) {
3848
            if (feed) {
3849
                int i;
3850

    
3851
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3852

    
3853
                for (i = 0; i < 62; i++) {
3854
                    char argbuf[256];
3855

    
3856
                    get_arg(argbuf, sizeof(argbuf), &p);
3857
                    if (!argbuf[0])
3858
                        break;
3859

    
3860
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3861
                    strcpy(feed->child_argv[i], argbuf);
3862
                }
3863

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

    
3866
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3867
                    "http://%s:%d/%s",
3868
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3869
                    inet_ntoa(my_http_addr.sin_addr),
3870
                    ntohs(my_http_addr.sin_port), feed->filename);
3871

    
3872
                if (ffserver_debug)
3873
                {
3874
                    int j;
3875
                    fprintf(stdout, "Launch commandline: ");
3876
                    for (j = 0; j <= i; j++)
3877
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3878
                    fprintf(stdout, "\n");
3879
                }
3880
            }
3881
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3882
            if (feed) {
3883
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3884
                feed->readonly = 1;
3885
            } else if (stream) {
3886
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3887
            }
3888
        } else if (!strcasecmp(cmd, "File")) {
3889
            if (feed) {
3890
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3891
            } else if (stream) {
3892
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3893
            }
3894
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3895
            if (feed) {
3896
                const char *p1;
3897
                double fsize;
3898

    
3899
                get_arg(arg, sizeof(arg), &p);
3900
                p1 = arg;
3901
                fsize = strtod(p1, (char **)&p1);
3902
                switch(toupper(*p1)) {
3903
                case 'K':
3904
                    fsize *= 1024;
3905
                    break;
3906
                case 'M':
3907
                    fsize *= 1024 * 1024;
3908
                    break;
3909
                case 'G':
3910
                    fsize *= 1024 * 1024 * 1024;
3911
                    break;
3912
                }
3913
                feed->feed_max_size = (int64_t)fsize;
3914
            }
3915
        } else if (!strcasecmp(cmd, "</Feed>")) {
3916
            if (!feed) {
3917
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3918
                        filename, line_num);
3919
                errors++;
3920
#if 0
3921
            } else {
3922
                /* Make sure that we start out clean */
3923
                if (unlink(feed->feed_filename) < 0
3924
                    && errno != ENOENT) {
3925
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3926
                        filename, line_num, feed->feed_filename, strerror(errno));
3927
                    errors++;
3928
                }
3929
#endif
3930
            }
3931
            feed = NULL;
3932
        } else if (!strcasecmp(cmd, "<Stream")) {
3933
            /*********************************************/
3934
            /* Stream related options */
3935
            char *q;
3936
            if (stream || feed) {
3937
                fprintf(stderr, "%s:%d: Already in a tag\n",
3938
                        filename, line_num);
3939
            } else {
3940
                stream = av_mallocz(sizeof(FFStream));
3941
                *last_stream = stream;
3942
                last_stream = &stream->next;
3943

    
3944
                get_arg(stream->filename, sizeof(stream->filename), &p);
3945
                q = strrchr(stream->filename, '>');
3946
                if (*q)
3947
                    *q = '\0';
3948
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3949
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3950
                memset(&video_enc, 0, sizeof(AVCodecContext));
3951
                audio_id = CODEC_ID_NONE;
3952
                video_id = CODEC_ID_NONE;
3953
                if (stream->fmt) {
3954
                    audio_id = stream->fmt->audio_codec;
3955
                    video_id = stream->fmt->video_codec;
3956
                }
3957
            }
3958
        } else if (!strcasecmp(cmd, "Feed")) {
3959
            get_arg(arg, sizeof(arg), &p);
3960
            if (stream) {
3961
                FFStream *sfeed;
3962

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

    
4081
                get_arg(arg, sizeof(arg), &p);
4082

    
4083
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4084
                    video_enc.rc_min_rate = minrate * 1000;
4085
                    video_enc.rc_max_rate = maxrate * 1000;
4086
                } else {
4087
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4088
                            filename, line_num, arg);
4089
                    errors++;
4090
                }
4091
            }
4092
        } else if (!strcasecmp(cmd, "Debug")) {
4093
            if (stream) {
4094
                get_arg(arg, sizeof(arg), &p);
4095
                video_enc.debug = strtol(arg,0,0);
4096
            }
4097
        } else if (!strcasecmp(cmd, "Strict")) {
4098
            if (stream) {
4099
                get_arg(arg, sizeof(arg), &p);
4100
                video_enc.strict_std_compliance = atoi(arg);
4101
            }
4102
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4103
            if (stream) {
4104
                get_arg(arg, sizeof(arg), &p);
4105
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4106
            }
4107
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4108
            if (stream) {
4109
                get_arg(arg, sizeof(arg), &p);
4110
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4111
            }
4112
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4113
            get_arg(arg, sizeof(arg), &p);
4114
            if (stream) {
4115
                video_enc.bit_rate = atoi(arg) * 1000;
4116
            }
4117
        } else if (!strcasecmp(cmd, "VideoSize")) {
4118
            get_arg(arg, sizeof(arg), &p);
4119
            if (stream) {
4120
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4121
                if ((video_enc.width % 16) != 0 ||
4122
                    (video_enc.height % 16) != 0) {
4123
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4124
                            filename, line_num);
4125
                    errors++;
4126
                }
4127
            }
4128
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4129
            get_arg(arg, sizeof(arg), &p);
4130
            if (stream) {
4131
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4132
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4133
            }
4134
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4135
            get_arg(arg, sizeof(arg), &p);
4136
            if (stream) {
4137
                video_enc.gop_size = atoi(arg);
4138
            }
4139
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4140
            if (stream) {
4141
                video_enc.gop_size = 1;
4142
            }
4143
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4144
            if (stream) {
4145
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4146
            }
4147
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4148
            if (stream) {
4149
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4150
                video_enc.flags |= CODEC_FLAG_4MV;
4151
            }
4152
        } else if (!strcasecmp(cmd, "BitExact")) {
4153
            if (stream) {
4154
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4155
            }
4156
        } else if (!strcasecmp(cmd, "DctFastint")) {
4157
            if (stream) {
4158
                video_enc.dct_algo  = FF_DCT_FASTINT;
4159
            }
4160
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4161
            if (stream) {
4162
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4163
            }
4164
        } else if (!strcasecmp(cmd, "Qscale")) {
4165
            get_arg(arg, sizeof(arg), &p);
4166
            if (stream) {
4167
                video_enc.flags |= CODEC_FLAG_QSCALE;
4168
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4169
            }
4170
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4171
            get_arg(arg, sizeof(arg), &p);
4172
            if (stream) {
4173
                video_enc.max_qdiff = atoi(arg);
4174
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4175
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4176
                            filename, line_num);
4177
                    errors++;
4178
                }
4179
            }
4180
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4181
            get_arg(arg, sizeof(arg), &p);
4182
            if (stream) {
4183
                video_enc.qmax = atoi(arg);
4184
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4185
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4186
                            filename, line_num);
4187
                    errors++;
4188
                }
4189
            }
4190
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4191
            get_arg(arg, sizeof(arg), &p);
4192
            if (stream) {
4193
                video_enc.qmin = atoi(arg);
4194
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4195
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4196
                            filename, line_num);
4197
                    errors++;
4198
                }
4199
            }
4200
        } else if (!strcasecmp(cmd, "LumaElim")) {
4201
            get_arg(arg, sizeof(arg), &p);
4202
            if (stream) {
4203
                video_enc.luma_elim_threshold = atoi(arg);
4204
            }
4205
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4206
            get_arg(arg, sizeof(arg), &p);
4207
            if (stream) {
4208
                video_enc.chroma_elim_threshold = atoi(arg);
4209
            }
4210
        } else if (!strcasecmp(cmd, "LumiMask")) {
4211
            get_arg(arg, sizeof(arg), &p);
4212
            if (stream) {
4213
                video_enc.lumi_masking = atof(arg);
4214
            }
4215
        } else if (!strcasecmp(cmd, "DarkMask")) {
4216
            get_arg(arg, sizeof(arg), &p);
4217
            if (stream) {
4218
                video_enc.dark_masking = atof(arg);
4219
            }
4220
        } else if (!strcasecmp(cmd, "NoVideo")) {
4221
            video_id = CODEC_ID_NONE;
4222
        } else if (!strcasecmp(cmd, "NoAudio")) {
4223
            audio_id = CODEC_ID_NONE;
4224
        } else if (!strcasecmp(cmd, "ACL")) {
4225
            IPAddressACL acl;
4226
            struct hostent *he;
4227

    
4228
            get_arg(arg, sizeof(arg), &p);
4229
            if (strcasecmp(arg, "allow") == 0) {
4230
                acl.action = IP_ALLOW;
4231
            } else if (strcasecmp(arg, "deny") == 0) {
4232
                acl.action = IP_DENY;
4233
            } else {
4234
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4235
                        filename, line_num, arg);
4236
                errors++;
4237
            }
4238

    
4239
            get_arg(arg, sizeof(arg), &p);
4240

    
4241
            he = gethostbyname(arg);
4242
            if (!he) {
4243
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4244
                        filename, line_num, arg);
4245
                errors++;
4246
            } else {
4247
                /* Only take the first */
4248
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4249
                acl.last = acl.first;
4250
            }
4251

    
4252
            get_arg(arg, sizeof(arg), &p);
4253

    
4254
            if (arg[0]) {
4255
                he = gethostbyname(arg);
4256
                if (!he) {
4257
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4258
                            filename, line_num, arg);
4259
                    errors++;
4260
                } else {
4261
                    /* Only take the first */
4262
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4263
                }
4264
            }
4265

    
4266
            if (!errors) {
4267
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4268
                IPAddressACL **naclp = 0;
4269

    
4270
                *nacl = acl;
4271
                nacl->next = 0;
4272

    
4273
                if (stream) {
4274
                    naclp = &stream->acl;
4275
                } else if (feed) {
4276
                    naclp = &feed->acl;
4277
                } else {
4278
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4279
                            filename, line_num);
4280
                    errors++;
4281
                }
4282

    
4283
                if (naclp) {
4284
                    while (*naclp)
4285
                        naclp = &(*naclp)->next;
4286

    
4287
                    *naclp = nacl;
4288
                }
4289
            }
4290
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4291
            get_arg(arg, sizeof(arg), &p);
4292
            if (stream) {
4293
                av_freep(&stream->rtsp_option);
4294
                /* XXX: av_strdup ? */
4295
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4296
                if (stream->rtsp_option) {
4297
                    strcpy(stream->rtsp_option, arg);
4298
                }
4299
            }
4300
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4301
            get_arg(arg, sizeof(arg), &p);
4302
            if (stream) {
4303
                if (!inet_aton(arg, &stream->multicast_ip)) {
4304
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
4305
                            filename, line_num, arg);
4306
                    errors++;
4307
                }
4308
                stream->is_multicast = 1;
4309
                stream->loop = 1; /* default is looping */
4310
            }
4311
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4312
            get_arg(arg, sizeof(arg), &p);
4313
            if (stream) {
4314
                stream->multicast_port = atoi(arg);
4315
            }
4316
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4317
            get_arg(arg, sizeof(arg), &p);
4318
            if (stream) {
4319
                stream->multicast_ttl = atoi(arg);
4320
            }
4321
        } else if (!strcasecmp(cmd, "NoLoop")) {
4322
            if (stream) {
4323
                stream->loop = 0;
4324
            }
4325
        } else if (!strcasecmp(cmd, "</Stream>")) {
4326
            if (!stream) {
4327
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4328
                        filename, line_num);
4329
                errors++;
4330
            }
4331
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4332
                if (audio_id != CODEC_ID_NONE) {
4333
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4334
                    audio_enc.codec_id = audio_id;
4335
                    add_codec(stream, &audio_enc);
4336
                }
4337
                if (video_id != CODEC_ID_NONE) {
4338
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4339
                    video_enc.codec_id = video_id;
4340
                    add_codec(stream, &video_enc);
4341
                }
4342
            }
4343
            stream = NULL;
4344
        } else if (!strcasecmp(cmd, "<Redirect")) {
4345
            /*********************************************/
4346
            char *q;
4347
            if (stream || feed || redirect) {
4348
                fprintf(stderr, "%s:%d: Already in a tag\n",
4349
                        filename, line_num);
4350
                errors++;
4351
            } else {
4352
                redirect = av_mallocz(sizeof(FFStream));
4353
                *last_stream = redirect;
4354
                last_stream = &redirect->next;
4355

    
4356
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4357
                q = strrchr(redirect->filename, '>');
4358
                if (*q)
4359
                    *q = '\0';
4360
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4361
            }
4362
        } else if (!strcasecmp(cmd, "URL")) {
4363
            if (redirect) {
4364
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4365
            }
4366
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4367
            if (!redirect) {
4368
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4369
                        filename, line_num);
4370
                errors++;
4371
            }
4372
            if (!redirect->feed_filename[0]) {
4373
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4374
                        filename, line_num);
4375
                errors++;
4376
            }
4377
            redirect = NULL;
4378
        } else if (!strcasecmp(cmd, "LoadModule")) {
4379
            get_arg(arg, sizeof(arg), &p);
4380
#ifdef HAVE_DLOPEN
4381
            load_module(arg);
4382
#else
4383
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4384
                    filename, line_num, arg);
4385
            errors++;
4386
#endif
4387
        } else {
4388
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4389
                    filename, line_num, cmd);
4390
            errors++;
4391
        }
4392
    }
4393

    
4394
    fclose(f);
4395
    if (errors)
4396
        return -1;
4397
    else
4398
        return 0;
4399
}
4400

    
4401

    
4402
#if 0
4403
static void write_packet(FFCodec *ffenc,
4404
                         uint8_t *buf, int size)
4405
{
4406
    PacketHeader hdr;
4407
    AVCodecContext *enc = &ffenc->enc;
4408
    uint8_t *wptr;
4409
    mk_header(&hdr, enc, size);
4410
    wptr = http_fifo.wptr;
4411
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4412
    fifo_write(&http_fifo, buf, size, &wptr);
4413
    /* atomic modification of wptr */
4414
    http_fifo.wptr = wptr;
4415
    ffenc->data_count += size;
4416
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4417
}
4418
#endif
4419

    
4420
static void show_banner(void)
4421
{
4422
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4423
}
4424

    
4425
static void show_help(void)
4426
{
4427
    show_banner();
4428
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4429
           "Hyper fast multi format Audio/Video streaming server\n"
4430
           "\n"
4431
           "-L            : print the LICENSE\n"
4432
           "-h            : this help\n"
4433
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4434
           );
4435
}
4436

    
4437
static void show_license(void)
4438
{
4439
    show_banner();
4440
    printf(
4441
    "FFmpeg is free software; you can redistribute it and/or\n"
4442
    "modify it under the terms of the GNU Lesser General Public\n"
4443
    "License as published by the Free Software Foundation; either\n"
4444
    "version 2.1 of the License, or (at your option) any later version.\n"
4445
    "\n"
4446
    "FFmpeg is distributed in the hope that it will be useful,\n"
4447
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4448
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4449
    "Lesser General Public License for more details.\n"
4450
    "\n"
4451
    "You should have received a copy of the GNU Lesser General Public\n"
4452
    "License along with FFmpeg; if not, write to the Free Software\n"
4453
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4454
    );
4455
}
4456

    
4457
static void handle_child_exit(int sig)
4458
{
4459
    pid_t pid;
4460
    int status;
4461

    
4462
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4463
        FFStream *feed;
4464

    
4465
        for (feed = first_feed; feed; feed = feed->next) {
4466
            if (feed->pid == pid) {
4467
                int uptime = time(0) - feed->pid_start;
4468

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

    
4472
                if (uptime < 30) {
4473
                    /* Turn off any more restarts */
4474
                    feed->child_argv = 0;
4475
                }
4476
            }
4477
        }
4478
    }
4479

    
4480
    need_to_start_children = 1;
4481
}
4482

    
4483
int main(int argc, char **argv)
4484
{
4485
    const char *config_filename;
4486
    int c;
4487
    struct sigaction sigact;
4488

    
4489
    av_register_all();
4490

    
4491
    config_filename = "/etc/ffserver.conf";
4492

    
4493
    my_program_name = argv[0];
4494
    my_program_dir = getcwd(0, 0);
4495
    ffserver_daemon = 1;
4496

    
4497
    for(;;) {
4498
        c = getopt(argc, argv, "ndLh?f:");
4499
        if (c == -1)
4500
            break;
4501
        switch(c) {
4502
        case 'L':
4503
            show_license();
4504
            exit(1);
4505
        case '?':
4506
        case 'h':
4507
            show_help();
4508
            exit(1);
4509
        case 'n':
4510
            no_launch = 1;
4511
            break;
4512
        case 'd':
4513
            ffserver_debug = 1;
4514
            ffserver_daemon = 0;
4515
            break;
4516
        case 'f':
4517
            config_filename = optarg;
4518
            break;
4519
        default:
4520
            exit(2);
4521
        }
4522
    }
4523

    
4524
    putenv("http_proxy");               /* Kill the http_proxy */
4525

    
4526
    srandom(gettime_ms() + (getpid() << 16));
4527

    
4528
    /* address on which the server will handle HTTP connections */
4529
    my_http_addr.sin_family = AF_INET;
4530
    my_http_addr.sin_port = htons (8080);
4531
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4532

    
4533
    /* address on which the server will handle RTSP connections */
4534
    my_rtsp_addr.sin_family = AF_INET;
4535
    my_rtsp_addr.sin_port = htons (5454);
4536
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4537

    
4538
    nb_max_connections = 5;
4539
    max_bandwidth = 1000;
4540
    first_stream = NULL;
4541
    logfilename[0] = '\0';
4542

    
4543
    memset(&sigact, 0, sizeof(sigact));
4544
    sigact.sa_handler = handle_child_exit;
4545
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4546
    sigaction(SIGCHLD, &sigact, 0);
4547

    
4548
    if (parse_ffconfig(config_filename) < 0) {
4549
        fprintf(stderr, "Incorrect config file - exiting.\n");
4550
        exit(1);
4551
    }
4552

    
4553
    build_file_streams();
4554

    
4555
    build_feed_streams();
4556

    
4557
    compute_bandwidth();
4558

    
4559
    /* put the process in background and detach it from its TTY */
4560
    if (ffserver_daemon) {
4561
        int pid;
4562

    
4563
        pid = fork();
4564
        if (pid < 0) {
4565
            perror("fork");
4566
            exit(1);
4567
        } else if (pid > 0) {
4568
            /* parent : exit */
4569
            exit(0);
4570
        } else {
4571
            /* child */
4572
            setsid();
4573
            chdir("/");
4574
            close(0);
4575
            open("/dev/null", O_RDWR);
4576
            if (strcmp(logfilename, "-") != 0) {
4577
                close(1);
4578
                dup(0);
4579
            }
4580
            close(2);
4581
            dup(0);
4582
        }
4583
    }
4584

    
4585
    /* signal init */
4586
    signal(SIGPIPE, SIG_IGN);
4587

    
4588
    /* open log file if needed */
4589
    if (logfilename[0] != '\0') {
4590
        if (!strcmp(logfilename, "-"))
4591
            logfile = stdout;
4592
        else
4593
            logfile = fopen(logfilename, "w");
4594
    }
4595

    
4596
    if (http_server() < 0) {
4597
        fprintf(stderr, "Could not start server\n");
4598
        exit(1);
4599
    }
4600

    
4601
    return 0;
4602
}