Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ dc032f33

History | View | Annotate | Download (149 KB)

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

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

    
42
#include "ffserver.h"
43

    
44
/* maximum number of simultaneous HTTP connections */
45
#define HTTP_MAX_CONNECTIONS 2000
46

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

    
57
    RTSPSTATE_WAIT_REQUEST,
58
    RTSPSTATE_SEND_REPLY,
59
    RTSPSTATE_SEND_PACKET,
60
};
61

    
62
const char *http_state[] = {
63
    "HTTP_WAIT_REQUEST",
64
    "HTTP_SEND_HEADER",
65

    
66
    "SEND_DATA_HEADER",
67
    "SEND_DATA",
68
    "SEND_DATA_TRAILER",
69
    "RECEIVE_DATA",
70
    "WAIT_FEED",
71
    "READY",
72

    
73
    "RTSP_WAIT_REQUEST",
74
    "RTSP_SEND_REPLY",
75
    "RTSP_SEND_PACKET",
76
};
77

    
78
#define IOBUFFER_INIT_SIZE 8192
79

    
80
/* coef for exponential mean for bitrate estimation in statistics */
81
#define AVG_COEF 0.9
82

    
83
/* timeouts are in ms */
84
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
85
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
86

    
87
#define SYNC_TIMEOUT (10 * 1000)
88

    
89
typedef struct {
90
    int64_t count1, count2;
91
    long time1, time2;
92
} DataRateData;
93

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

    
148
    /* RTP/UDP specific */
149
    URLContext *rtp_handles[MAX_STREAMS];
150

    
151
    /* RTP/TCP specific */
152
    struct HTTPContext *rtsp_c;
153
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
154
} HTTPContext;
155

    
156
static AVFrame dummy_frame;
157

    
158
/* each generated stream is described here */
159
enum StreamType {
160
    STREAM_TYPE_LIVE,
161
    STREAM_TYPE_STATUS,
162
    STREAM_TYPE_REDIRECT,
163
};
164

    
165
enum IPAddressAction {
166
    IP_ALLOW = 1,
167
    IP_DENY,
168
};
169

    
170
typedef struct IPAddressACL {
171
    struct IPAddressACL *next;
172
    enum IPAddressAction action;
173
    /* These are in host order */
174
    struct in_addr first;
175
    struct in_addr last;
176
} IPAddressACL;
177

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

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

    
226
typedef struct FeedData {
227
    long long data_count;
228
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
229
} FeedData;
230

    
231
struct sockaddr_in my_http_addr;
232
struct sockaddr_in my_rtsp_addr;
233

    
234
char logfilename[1024];
235
HTTPContext *first_http_ctx;
236
FFStream *first_feed;   /* contains only feeds */
237
FFStream *first_stream; /* contains all streams, including feeds */
238

    
239
static void new_connection(int server_fd, int is_rtsp);
240
static void close_connection(HTTPContext *c);
241

    
242
/* HTTP handling */
243
static int handle_connection(HTTPContext *c);
244
static int http_parse_request(HTTPContext *c);
245
static int http_send_data(HTTPContext *c);
246
static void compute_stats(HTTPContext *c);
247
static int open_input_stream(HTTPContext *c, const char *info);
248
static int http_start_receive_data(HTTPContext *c);
249
static int http_receive_data(HTTPContext *c);
250

    
251
/* RTSP handling */
252
static int rtsp_parse_request(HTTPContext *c);
253
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
254
static void rtsp_cmd_options(HTTPContext *c, const char *url);
255
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
256
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
257
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
258
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
259

    
260
/* SDP handling */
261
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
262
                                   struct in_addr my_ip);
263

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

    
272
static const char *my_program_name;
273
static const char *my_program_dir;
274

    
275
static int ffserver_debug;
276
static int ffserver_daemon;
277
static int no_launch;
278
static int need_to_start_children;
279

    
280
int nb_max_connections;
281
int nb_connections;
282

    
283
int max_bandwidth;
284
int current_bandwidth;
285

    
286
static long cur_time;           // Making this global saves on passing it around everywhere
287

    
288
static long gettime_ms(void)
289
{
290
    struct timeval tv;
291

    
292
    gettimeofday(&tv,NULL);
293
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
294
}
295

    
296
static FILE *logfile = NULL;
297

    
298
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...) 
299
{
300
    va_list ap;
301
    va_start(ap, fmt);
302
    
303
    if (logfile) {
304
        vfprintf(logfile, fmt, ap);
305
        fflush(logfile);
306
    }
307
    va_end(ap);
308
}
309

    
310
static char *ctime1(char *buf2)
311
{
312
    time_t ti;
313
    char *p;
314

    
315
    ti = time(NULL);
316
    p = ctime(&ti);
317
    strcpy(buf2, p);
318
    p = buf2 + strlen(p) - 1;
319
    if (*p == '\n')
320
        *p = '\0';
321
    return buf2;
322
}
323

    
324
static void log_connection(HTTPContext *c)
325
{
326
    char buf2[32];
327

    
328
    if (c->suppress_log) 
329
        return;
330

    
331
    http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
332
             inet_ntoa(c->from_addr.sin_addr), 
333
             ctime1(buf2), c->method, c->url, 
334
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
335
}
336

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

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

    
361
static int get_longterm_datarate(DataRateData *drd, int64_t count)
362
{
363
    /* You get the first 3 seconds flat out */
364
    if (cur_time - drd->time1 < 3000)
365
        return 0;
366
    return compute_datarate(drd, count);
367
}
368

    
369

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

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

    
379
            feed->pid = fork();
380

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

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

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

    
405
                pstrcpy(pathname, sizeof(pathname), my_program_name);
406

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

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

    
418
                signal(SIGPIPE, SIG_DFL);
419

    
420
                execvp(pathname, feed->child_argv);
421

    
422
                _exit(1);
423
            }
424
        }
425
    }
426
}
427

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

    
433
    server_fd = socket(AF_INET,SOCK_STREAM,0);
434
    if (server_fd < 0) {
435
        perror ("socket");
436
        return -1;
437
    }
438
        
439
    tmp = 1;
440
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
441

    
442
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
443
        char bindmsg[32];
444
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
445
        perror (bindmsg);
446
        close(server_fd);
447
        return -1;
448
    }
449
  
450
    if (listen (server_fd, 5) < 0) {
451
        perror ("listen");
452
        close(server_fd);
453
        return -1;
454
    }
455
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
456

    
457
    return server_fd;
458
}
459

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

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

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

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

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

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

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

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

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

    
526
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
527
    if (rtsp_server_fd < 0)
528
        return -1;
529
    
530
    http_log("ffserver started.\n");
531

    
532
    start_children(first_feed);
533

    
534
    first_http_ctx = NULL;
535
    nb_connections = 0;
536

    
537
    start_multicast();
538

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

    
545
        poll_entry->fd = rtsp_server_fd;
546
        poll_entry->events = POLLIN;
547
        poll_entry++;
548

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

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

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

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

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

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

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

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

    
658
    len = sizeof(from_addr);
659
    fd = accept(server_fd, (struct sockaddr *)&from_addr, 
660
                &len);
661
    if (fd < 0)
662
        return;
663
    fcntl(fd, F_SETFL, O_NONBLOCK);
664

    
665
    /* XXX: should output a warning page when coming
666
       close to the connection limit */
667
    if (nb_connections >= nb_max_connections)
668
        goto fail;
669
    
670
    /* add a new connection */
671
    c = av_mallocz(sizeof(HTTPContext));
672
    if (!c)
673
        goto fail;
674
    
675
    c->fd = fd;
676
    c->poll_entry = NULL;
677
    c->from_addr = from_addr;
678
    c->buffer_size = IOBUFFER_INIT_SIZE;
679
    c->buffer = av_malloc(c->buffer_size);
680
    if (!c->buffer)
681
        goto fail;
682

    
683
    c->next = first_http_ctx;
684
    first_http_ctx = c;
685
    nb_connections++;
686
    
687
    start_wait_request(c, is_rtsp);
688

    
689
    return;
690

    
691
 fail:
692
    if (c) {
693
        av_free(c->buffer);
694
        av_free(c);
695
    }
696
    close(fd);
697
}
698

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

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

    
718
    /* remove references, if any (XXX: do it faster) */
719
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
720
        if (c1->rtsp_c == c)
721
            c1->rtsp_c = NULL;
722
    }
723

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

    
738
    /* free RTP output streams if any */
739
    nb_streams = 0;
740
    if (c->stream) 
741
        nb_streams = c->stream->nb_streams;
742
    
743
    for(i=0;i<nb_streams;i++) {
744
        ctx = c->rtp_ctx[i];
745
        if (ctx) {
746
            av_write_trailer(ctx);
747
            av_free(ctx);
748
        }
749
        h = c->rtp_handles[i];
750
        if (h) {
751
            url_close(h);
752
        }
753
    }
754
    
755
    ctx = &c->fmt_ctx;
756

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

    
767
    for(i=0; i<ctx->nb_streams; i++) 
768
        av_free(ctx->streams[i]) ; 
769

    
770
    if (c->stream)
771
        current_bandwidth -= c->stream->bandwidth;
772
    av_freep(&c->pb_buffer);
773
    av_freep(&c->packet_buffer);
774
    av_free(c->buffer);
775
    av_free(c);
776
    nb_connections--;
777
}
778

    
779
static int handle_connection(HTTPContext *c)
780
{
781
    int len, ret;
782
    
783
    switch(c->state) {
784
    case HTTPSTATE_WAIT_REQUEST:
785
    case RTSPSTATE_WAIT_REQUEST:
786
        /* timeout ? */
787
        if ((c->timeout - cur_time) < 0)
788
            return -1;
789
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
790
            return -1;
791

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

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

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

    
857
    case HTTPSTATE_SEND_DATA:
858
    case HTTPSTATE_SEND_DATA_HEADER:
859
    case HTTPSTATE_SEND_DATA_TRAILER:
860
        /* for packetized output, we consider we can always write (the
861
           input streams sets the speed). It may be better to verify
862
           that we do not rely too much on the kernel queues */
863
        if (!c->is_packetized) {
864
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
865
                return -1;
866
            
867
            /* no need to read if no events */
868
            if (!(c->poll_entry->revents & POLLOUT))
869
                return 0;
870
        }
871
        if (http_send_data(c) < 0)
872
            return -1;
873
        break;
874
    case HTTPSTATE_RECEIVE_DATA:
875
        /* no need to read if no events */
876
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
877
            return -1;
878
        if (!(c->poll_entry->revents & POLLIN))
879
            return 0;
880
        if (http_receive_data(c) < 0)
881
            return -1;
882
        break;
883
    case HTTPSTATE_WAIT_FEED:
884
        /* no need to read if no events */
885
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
886
            return -1;
887

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

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

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

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

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

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

    
965
                q += 20;
966

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

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

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

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

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

    
992
        p++;
993
    }
994

    
995
    return 0;
996
}
997

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

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

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

    
1014
        /* Potential stream */
1015

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

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

    
1033
    return best;
1034
}
1035

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

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

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

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

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

    
1071
    return action_required;
1072
}
1073

    
1074

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

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

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

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

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

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

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

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

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

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

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

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

    
1186
    p = c->buffer;
1187
    get_word(cmd, sizeof(cmd), (const char **)&p);
1188
    pstrcpy(c->method, sizeof(c->method), cmd);
1189

    
1190
    if (!strcmp(cmd, "GET"))
1191
        post = 0;
1192
    else if (!strcmp(cmd, "POST"))
1193
        post = 1;
1194
    else
1195
        return -1;
1196

    
1197
    get_word(url, sizeof(url), (const char **)&p);
1198
    pstrcpy(c->url, sizeof(c->url), url);
1199

    
1200
    get_word(protocol, sizeof(protocol), (const char **)&p);
1201
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1202
        return -1;
1203

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

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

    
1230
        p++;
1231
    }
1232

    
1233
    redir_type = REDIR_NONE;
1234
    if (match_ext(filename, "asx")) {
1235
        redir_type = REDIR_ASX;
1236
        filename[strlen(filename)-1] = 'f';
1237
    } else if (match_ext(filename, "asf") &&
1238
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1239
        /* if this isn't WMP or lookalike, return the redirector file */
1240
        redir_type = REDIR_ASF;
1241
    } else if (match_ext(filename, "rpm,ram")) {
1242
        redir_type = REDIR_RAM;
1243
        strcpy(filename + strlen(filename)-2, "m");
1244
    } else if (match_ext(filename, "rtsp")) {
1245
        redir_type = REDIR_RTSP;
1246
        compute_real_filename(filename, sizeof(url) - 1);
1247
    } else if (match_ext(filename, "sdp")) {
1248
        redir_type = REDIR_SDP;
1249
        compute_real_filename(filename, sizeof(url) - 1);
1250
    }
1251
    
1252
    stream = first_stream;
1253
    while (stream != NULL) {
1254
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1255
            break;
1256
        stream = stream->next;
1257
    }
1258
    if (stream == NULL) {
1259
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1260
        goto send_error;
1261
    }
1262

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

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

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

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

    
1295
    if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1296
        current_bandwidth += stream->bandwidth;
1297
    }
1298
    
1299
    if (post == 0 && max_bandwidth < current_bandwidth) {
1300
        c->http_error = 200;
1301
        q = c->buffer;
1302
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1303
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1304
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1305
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1306
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "The server is too busy to serve your request at this time.<p>\r\n");
1307
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1308
            current_bandwidth, max_bandwidth);
1309
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1310

    
1311
        /* prepare output buffer */
1312
        c->buffer_ptr = c->buffer;
1313
        c->buffer_end = q;
1314
        c->state = HTTPSTATE_SEND_HEADER;
1315
        return 0;
1316
    }
1317
    
1318
    if (redir_type != REDIR_NONE) {
1319
        char *hostinfo = 0;
1320
        
1321
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1322
            if (strncasecmp(p, "Host:", 5) == 0) {
1323
                hostinfo = p + 5;
1324
                break;
1325
            }
1326
            p = strchr(p, '\n');
1327
            if (!p)
1328
                break;
1329

    
1330
            p++;
1331
        }
1332

    
1333
        if (hostinfo) {
1334
            char *eoh;
1335
            char hostbuf[260];
1336

    
1337
            while (isspace(*hostinfo))
1338
                hostinfo++;
1339

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

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

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

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

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

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

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

    
1438
    stream->conns_served++;
1439

    
1440
    /* XXX: add there authenticate and IP match */
1441

    
1442
    if (post) {
1443
        /* if post, it means a feed is being sent */
1444
        if (!stream->is_feed) {
1445
            /* However it might be a status report from WMP! Lets log the data
1446
             * as it might come in handy one day
1447
             */
1448
            char *logline = 0;
1449
            int client_id = 0;
1450
            
1451
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1452
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1453
                    logline = p;
1454
                    break;
1455
                }
1456
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1457
                    client_id = strtol(p + 18, 0, 10);
1458
                }
1459
                p = strchr(p, '\n');
1460
                if (!p)
1461
                    break;
1462

    
1463
                p++;
1464
            }
1465

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

    
1469
                logline += 17;
1470

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

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

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

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

    
1492
                if (wmpc) {
1493
                    if (modify_current_stream(wmpc, ratebuf)) {
1494
                        wmpc->switch_pending = 1;
1495
                    }
1496
                }
1497
            }
1498
            
1499
            snprintf(msg, sizeof(msg), "POST command not handled");
1500
            c->stream = 0;
1501
            goto send_error;
1502
        }
1503
        if (http_start_receive_data(c) < 0) {
1504
            snprintf(msg, sizeof(msg), "could not open feed");
1505
            goto send_error;
1506
        }
1507
        c->http_error = 0;
1508
        c->state = HTTPSTATE_RECEIVE_DATA;
1509
        return 0;
1510
    }
1511

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

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

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

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

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

    
1539
        c->wmp_client_id = random() & 0x7fffffff;
1540

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

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

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

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

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

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

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

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

    
1623
        if (stream->feed != stream) {
1624
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1625
            eosf = sfilename + strlen(sfilename);
1626
            if (eosf - sfilename >= 4) {
1627
                if (strcmp(eosf - 4, ".asf") == 0) {
1628
                    strcpy(eosf - 4, ".asx");
1629
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1630
                    strcpy(eosf - 3, ".ram");
1631
                } else if (stream->fmt == &rtp_mux) {
1632
                    /* generate a sample RTSP director if
1633
                       unicast. Generate an SDP redirector if
1634
                       multicast */
1635
                    eosf = strrchr(sfilename, '.');
1636
                    if (!eosf)
1637
                        eosf = sfilename + strlen(sfilename);
1638
                    if (stream->is_multicast)
1639
                        strcpy(eosf, ".sdp");
1640
                    else
1641
                        strcpy(eosf, ".rtsp");
1642
                }
1643
            }
1644
            
1645
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
1646
                         sfilename, stream->filename);
1647
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1648
                        stream->conns_served);
1649
            fmt_bytecount(pb, stream->bytes_served);
1650
            switch(stream->stream_type) {
1651
            case STREAM_TYPE_LIVE:
1652
                {
1653
                    int audio_bit_rate = 0;
1654
                    int video_bit_rate = 0;
1655
                    const char *audio_codec_name = "";
1656
                    const char *video_codec_name = "";
1657
                    const char *audio_codec_name_extra = "";
1658
                    const char *video_codec_name_extra = "";
1659

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

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

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

    
1721
                    /* This is somewhat linux specific I guess */
1722
                    snprintf(ps_cmd, sizeof(ps_cmd), 
1723
                             "ps -o \"%%cpu,cputime\" --no-headers %d", 
1724
                             stream->pid);
1725
                    
1726
                    pid_stat = popen(ps_cmd, "r");
1727
                    if (pid_stat) {
1728
                        char cpuperc[10];
1729
                        char cpuused[64];
1730
                        
1731
                        if (fscanf(pid_stat, "%10s %64s", cpuperc, 
1732
                                   cpuused) == 2) {
1733
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1734
                                         cpuperc, cpuused);
1735
                        }
1736
                        fclose(pid_stat);
1737
                    }
1738
                }
1739
#endif
1740

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

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

    
1751
                parameters[0] = 0;
1752

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

    
1770
        }       
1771
        stream = stream->next;
1772
    }
1773
    
1774
#if 0
1775
    {
1776
        float avg;
1777
        AVCodecContext *enc;
1778
        char buf[1024];
1779
        
1780
        /* feed status */
1781
        stream = first_feed;
1782
        while (stream != NULL) {
1783
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1784
            url_fprintf(pb, "<TABLE>\n");
1785
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1786
            for(i=0;i<stream->nb_streams;i++) {
1787
                AVStream *st = stream->streams[i];
1788
                FeedData *fdata = st->priv_data;
1789
                enc = &st->codec;
1790
            
1791
                avcodec_string(buf, sizeof(buf), enc);
1792
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1793
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1794
                    avg /= enc->frame_size;
1795
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
1796
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1797
            }
1798
            url_fprintf(pb, "</TABLE>\n");
1799
            stream = stream->next_feed;
1800
        }
1801
    }
1802
#endif
1803

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

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

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

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

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

    
1834
        i++;
1835
        p = inet_ntoa(c1->from_addr.sin_addr);
1836
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>", 
1837
                    i, 
1838
                    c1->stream ? c1->stream->filename : "", 
1839
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1840
                    p, 
1841
                    c1->protocol,
1842
                    http_state[c1->state]);
1843
        fmt_bytecount(pb, bitrate);
1844
        url_fprintf(pb, "<td align=right>");
1845
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1846
        url_fprintf(pb, "<td align=right>");
1847
        fmt_bytecount(pb, c1->data_count);
1848
        url_fprintf(pb, "\n");
1849
        c1 = c1->next;
1850
    }
1851
    url_fprintf(pb, "</TABLE>\n");
1852
    
1853
    /* date */
1854
    ti = time(NULL);
1855
    p = ctime(&ti);
1856
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1857
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1858

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

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

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

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

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

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

    
1921
    /* open stream */
1922
    if (av_open_input_file(&s, input_filename, c->stream->ifmt, 
1923
                           buf_size, c->stream->ap_in) < 0) {
1924
        http_log("%s not found", input_filename);
1925
        return -1;
1926
    }
1927
    c->fmt_in = s;
1928
    
1929
    /* open each parser */
1930
    for(i=0;i<s->nb_streams;i++)
1931
        open_parser(s, i);
1932

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

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

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

    
1961
/* return the estimated time at which the current packet must be sent
1962
   (in us) */
1963
static int64_t get_packet_send_clock(HTTPContext *c)
1964
{
1965
    int bytes_left, bytes_sent, frame_bytes;
1966
    
1967
    frame_bytes = c->cur_frame_bytes;
1968
    if (frame_bytes <= 0) {
1969
        return c->cur_pts;
1970
    } else {
1971
        bytes_left = c->buffer_end - c->buffer_ptr;
1972
        bytes_sent = frame_bytes - bytes_left;
1973
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1974
    }
1975
}
1976

    
1977

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

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

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

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

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

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

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

    
2036
        c->state = HTTPSTATE_SEND_DATA;
2037
        c->last_packet_sent = 0;
2038
        break;
2039
    case HTTPSTATE_SEND_DATA:
2040
        /* find a new packet */
2041
        {
2042
            AVPacket pkt;
2043
            
2044
            /* read a packet from the input stream */
2045
            if (c->stream->feed) {
2046
                ffm_set_write_index(c->fmt_in, 
2047
                                    c->stream->feed->feed_write_index,
2048
                                    c->stream->feed->feed_size);
2049
            }
2050

    
2051
            if (c->stream->max_time && 
2052
                c->stream->max_time + c->start_time - cur_time < 0) {
2053
                /* We have timed out */
2054
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
2055
            } else {
2056
            redo:
2057
                if (av_read_frame(c->fmt_in, &pkt) < 0) {
2058
                    if (c->stream->feed && c->stream->feed->feed_opened) {
2059
                        /* if coming from feed, it means we reached the end of the
2060
                           ffm file, so must wait for more data */
2061
                        c->state = HTTPSTATE_WAIT_FEED;
2062
                        return 1; /* state changed */
2063
                    } else {
2064
                        if (c->stream->loop) {
2065
                            av_close_input_file(c->fmt_in);
2066
                            c->fmt_in = NULL;
2067
                            if (open_input_stream(c, "") < 0)
2068
                                goto no_loop;
2069
                            goto redo;
2070
                        } else {
2071
                        no_loop:
2072
                            /* must send trailer now because eof or error */
2073
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2074
                        }
2075
                    }
2076
                } else {
2077
                    /* update first pts if needed */
2078
                    if (c->first_pts == AV_NOPTS_VALUE) {
2079
                        c->first_pts = pkt.dts;
2080
                        c->start_time = cur_time;
2081
                    }
2082
                    /* send it to the appropriate stream */
2083
                    if (c->stream->feed) {
2084
                        /* if coming from a feed, select the right stream */
2085
                        if (c->switch_pending) {
2086
                            c->switch_pending = 0;
2087
                            for(i=0;i<c->stream->nb_streams;i++) {
2088
                                if (c->switch_feed_streams[i] == pkt.stream_index) {
2089
                                    if (pkt.flags & PKT_FLAG_KEY) {
2090
                                        do_switch_stream(c, i);
2091
                                    }
2092
                                }
2093
                                if (c->switch_feed_streams[i] >= 0) {
2094
                                    c->switch_pending = 1;
2095
                                }
2096
                            }
2097
                        }
2098
                        for(i=0;i<c->stream->nb_streams;i++) {
2099
                            if (c->feed_streams[i] == pkt.stream_index) {
2100
                                pkt.stream_index = i;
2101
                                if (pkt.flags & PKT_FLAG_KEY) {
2102
                                    c->got_key_frame |= 1 << i;
2103
                                }
2104
                                /* See if we have all the key frames, then 
2105
                                 * we start to send. This logic is not quite
2106
                                 * right, but it works for the case of a 
2107
                                 * single video stream with one or more
2108
                                 * audio streams (for which every frame is 
2109
                                 * typically a key frame). 
2110
                                 */
2111
                                if (!c->stream->send_on_key || 
2112
                                    ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2113
                                    goto send_it;
2114
                                }
2115
                            }
2116
                        }
2117
                    } else {
2118
                        AVCodecContext *codec;
2119
                        
2120
                    send_it:
2121
                        /* specific handling for RTP: we use several
2122
                           output stream (one for each RTP
2123
                           connection). XXX: need more abstract handling */
2124
                        if (c->is_packetized) {
2125
                            AVStream *st;
2126
                            /* compute send time and duration */
2127
                            st = c->fmt_in->streams[pkt.stream_index];
2128
                            c->cur_pts = pkt.dts;
2129
                            if (st->start_time != AV_NOPTS_VALUE)
2130
                                c->cur_pts -= st->start_time;
2131
                            c->cur_frame_duration = pkt.duration;
2132
#if 0
2133
                            printf("index=%d pts=%0.3f duration=%0.6f\n",
2134
                                   pkt.stream_index,
2135
                                   (double)c->cur_pts / 
2136
                                   AV_TIME_BASE,
2137
                                   (double)c->cur_frame_duration / 
2138
                                   AV_TIME_BASE);
2139
#endif
2140
                            /* find RTP context */
2141
                            c->packet_stream_index = pkt.stream_index;
2142
                            ctx = c->rtp_ctx[c->packet_stream_index];
2143
                            if(!ctx) {
2144
                              av_free_packet(&pkt);
2145
                              break;
2146
                            }
2147
                            codec = &ctx->streams[0]->codec;
2148
                            /* only one stream per RTP connection */
2149
                            pkt.stream_index = 0;
2150
                        } else {
2151
                            ctx = &c->fmt_ctx;
2152
                            /* Fudge here */
2153
                            codec = &ctx->streams[pkt.stream_index]->codec;
2154
                        }
2155
                        
2156
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2157
                        if (c->is_packetized) {
2158
                            int max_packet_size;
2159
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2160
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2161
                            else
2162
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2163
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2164
                        } else {
2165
                            ret = url_open_dyn_buf(&ctx->pb);
2166
                        }
2167
                        if (ret < 0) {
2168
                            /* XXX: potential leak */
2169
                            return -1;
2170
                        }
2171
                        if (av_write_frame(ctx, &pkt)) {
2172
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2173
                        }
2174
                        
2175
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2176
                        c->cur_frame_bytes = len;
2177
                        c->buffer_ptr = c->pb_buffer;
2178
                        c->buffer_end = c->pb_buffer + len;
2179
                        
2180
                        codec->frame_number++;
2181
                        if (len == 0)
2182
                            goto redo;
2183
                    }
2184
                    av_free_packet(&pkt);
2185
                }
2186
            }
2187
        }
2188
        break;
2189
    default:
2190
    case HTTPSTATE_SEND_DATA_TRAILER:
2191
        /* last packet test ? */
2192
        if (c->last_packet_sent || c->is_packetized)
2193
            return -1;
2194
        ctx = &c->fmt_ctx;
2195
        /* prepare header */
2196
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2197
            /* XXX: potential leak */
2198
            return -1;
2199
        }
2200
        av_write_trailer(ctx);
2201
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2202
        c->buffer_ptr = c->pb_buffer;
2203
        c->buffer_end = c->pb_buffer + len;
2204

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

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

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

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

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

    
2256
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2257
                    /* RTP packets are sent inside the RTSP TCP connection */
2258
                    ByteIOContext pb1, *pb = &pb1;
2259
                    int interleaved_index, size;
2260
                    uint8_t header[4];
2261
                    HTTPContext *rtsp_c;
2262
                    
2263
                    rtsp_c = c->rtsp_c;
2264
                    /* if no RTSP connection left, error */
2265
                    if (!rtsp_c)
2266
                        return -1;
2267
                    /* if already sending something, then wait. */
2268
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2269
                        break;
2270
                    }
2271
                    if (url_open_dyn_buf(pb) < 0)
2272
                        goto fail1;
2273
                    interleaved_index = c->packet_stream_index * 2;
2274
                    /* RTCP packets are sent at odd indexes */
2275
                    if (c->buffer_ptr[1] == 200)
2276
                        interleaved_index++;
2277
                    /* write RTSP TCP header */
2278
                    header[0] = '$';
2279
                    header[1] = interleaved_index;
2280
                    header[2] = len >> 8;
2281
                    header[3] = len;
2282
                    put_buffer(pb, header, 4);
2283
                    /* write RTP packet data */
2284
                    c->buffer_ptr += 4;
2285
                    put_buffer(pb, c->buffer_ptr, len);
2286
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2287
                    /* prepare asynchronous TCP sending */
2288
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2289
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2290
                    c->buffer_ptr += len;
2291
                    
2292
                    /* send everything we can NOW */
2293
                    len = write(rtsp_c->fd, rtsp_c->packet_buffer_ptr, 
2294
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr);
2295
                    if (len > 0) {
2296
                        rtsp_c->packet_buffer_ptr += len;
2297
                    }
2298
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2299
                        /* if we could not send all the data, we will
2300
                           send it later, so a new state is needed to
2301
                           "lock" the RTSP TCP connection */
2302
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2303
                        break;
2304
                    } else {
2305
                        /* all data has been sent */
2306
                        av_freep(&c->packet_buffer);
2307
                    }
2308
                } else {
2309
                    /* send RTP packet directly in UDP */
2310
                    c->buffer_ptr += 4;
2311
                    url_write(c->rtp_handles[c->packet_stream_index], 
2312
                              c->buffer_ptr, len);
2313
                    c->buffer_ptr += len;
2314
                    /* here we continue as we can send several packets per 10 ms slot */
2315
                }
2316
            } else {
2317
                /* TCP data output */
2318
                len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2319
                if (len < 0) {
2320
                    if (errno != EAGAIN && errno != EINTR) {
2321
                        /* error : close connection */
2322
                        return -1;
2323
                    } else {
2324
                        return 0;
2325
                    }
2326
                } else {
2327
                    c->buffer_ptr += len;
2328
                }
2329
                c->data_count += len;
2330
                update_datarate(&c->datarate, c->data_count);
2331
                if (c->stream)
2332
                    c->stream->bytes_served += len;
2333
                break;
2334
            }
2335
        }
2336
    } /* for(;;) */
2337
    return 0;
2338
}
2339

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

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

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

    
2351
    /* open feed */
2352
    fd = open(c->stream->feed_filename, O_RDWR);
2353
    if (fd < 0)
2354
        return -1;
2355
    c->feed_fd = fd;
2356
    
2357
    c->stream->feed_write_index = ffm_read_write_index(fd);
2358
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2359
    lseek(fd, 0, SEEK_SET);
2360

    
2361
    /* init buffer input */
2362
    c->buffer_ptr = c->buffer;
2363
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2364
    c->stream->feed_opened = 1;
2365
    return 0;
2366
}
2367
    
2368
static int http_receive_data(HTTPContext *c)
2369
{
2370
    HTTPContext *c1;
2371

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

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

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

    
2399
    if (c->buffer_ptr >= c->buffer_end) {
2400
        FFStream *feed = c->stream;
2401
        /* a packet has been received : write it in the store, except
2402
           if header */
2403
        if (c->data_count > FFM_PACKET_SIZE) {
2404
            
2405
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2406
            /* XXX: use llseek or url_seek */
2407
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2408
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2409
            
2410
            feed->feed_write_index += FFM_PACKET_SIZE;
2411
            /* update file size */
2412
            if (feed->feed_write_index > c->stream->feed_size)
2413
                feed->feed_size = feed->feed_write_index;
2414

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

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

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

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

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

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

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

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

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

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

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

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

    
2490
    switch(error_number) {
2491
#define DEF(n, c, s) case c: str = s; break; 
2492
#include "rtspcodes.h"
2493
#undef DEF
2494
    default:
2495
        str = "Unknown Error";
2496
        break;
2497
    }
2498
     
2499
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2500
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2501

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

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

    
2518
static int rtsp_parse_request(HTTPContext *c)
2519
{
2520
    const char *p, *p1, *p2;
2521
    char cmd[32];
2522
    char url[1024];
2523
    char protocol[32];
2524
    char line[1024];
2525
    ByteIOContext pb1;
2526
    int len;
2527
    RTSPHeader header1, *header = &header1;
2528
    
2529
    c->buffer_ptr[0] = '\0';
2530
    p = c->buffer;
2531
    
2532
    get_word(cmd, sizeof(cmd), &p);
2533
    get_word(url, sizeof(url), &p);
2534
    get_word(protocol, sizeof(protocol), &p);
2535

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

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

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

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

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

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

    
2610
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2611
   AVFormatContext */
2612
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
2613
                                   struct in_addr my_ip)
2614
{
2615
    ByteIOContext pb1, *pb = &pb1;
2616
    int i, payload_type, port, private_payload_type, j;
2617
    const char *ipstr, *title, *mediatype;
2618
    AVStream *st;
2619
    
2620
    if (url_open_dyn_buf(pb) < 0)
2621
        return -1;
2622
    
2623
    /* general media info */
2624

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

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

    
2710
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2711
{
2712
    FFStream *stream;
2713
    char path1[1024];
2714
    const char *path;
2715
    uint8_t *content;
2716
    int content_length, len;
2717
    struct sockaddr_in my_addr;
2718
    
2719
    /* find which url is asked */
2720
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2721
    path = path1;
2722
    if (*path == '/')
2723
        path++;
2724

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

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

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

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

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

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

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

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

    
2780
static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2781
                           RTSPHeader *h)
2782
{
2783
    FFStream *stream;
2784
    int stream_index, port;
2785
    char buf[1024];
2786
    char path1[1024];
2787
    const char *path;
2788
    HTTPContext *rtp_c;
2789
    RTSPTransportField *th;
2790
    struct sockaddr_in dest_addr;
2791
    RTSPActionServerSetup setup;
2792
    
2793
    /* find which url is asked */
2794
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2795
    path = path1;
2796
    if (*path == '/')
2797
        path++;
2798

    
2799
    /* now check each stream */
2800
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2801
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2802
            /* accept aggregate filenames only if single stream */
2803
            if (!strcmp(path, stream->filename)) {
2804
                if (stream->nb_streams != 1) {
2805
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2806
                    return;
2807
                }
2808
                stream_index = 0;
2809
                goto found;
2810
            }
2811
                
2812
            for(stream_index = 0; stream_index < stream->nb_streams;
2813
                stream_index++) {
2814
                snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2815
                         stream->filename, stream_index);
2816
                if (!strcmp(path, buf))
2817
                    goto found;
2818
            }
2819
        }
2820
    }
2821
    /* no stream found */
2822
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2823
    return;
2824
 found:
2825

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

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

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

    
2852
        /* open input stream */
2853
        if (open_input_stream(rtp_c, "") < 0) {
2854
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2855
            return;
2856
        }
2857
    }
2858
    
2859
    /* test if stream is OK (test needed because several SETUP needs
2860
       to be done for a given file) */
2861
    if (rtp_c->stream != stream) {
2862
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2863
        return;
2864
    }
2865
    
2866
    /* test if stream is already set up */
2867
    if (rtp_c->rtp_ctx[stream_index]) {
2868
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2869
        return;
2870
    }
2871

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

    
2880
    /* setup default options */
2881
    setup.transport_option[0] = '\0';
2882
    dest_addr = rtp_c->from_addr;
2883
    dest_addr.sin_port = htons(th->client_port_min);
2884
    
2885
    /* add transport option if needed */
2886
    if (ff_rtsp_callback) {
2887
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2888
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2889
                             (char *)&setup, sizeof(setup),
2890
                             stream->rtsp_option) < 0) {
2891
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2892
            return;
2893
        }
2894
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2895
    }
2896
    
2897
    /* setup stream */
2898
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2899
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2900
        return;
2901
    }
2902

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

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

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

    
2932

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

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

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

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

    
2969
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2970
    if (!rtp_c) {
2971
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2972
        return;
2973
    }
2974
    
2975
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2976
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2977
        rtp_c->state != HTTPSTATE_READY) {
2978
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2979
        return;
2980
    }
2981

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

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

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

    
3003
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3004
    if (!rtp_c) {
3005
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3006
        return;
3007
    }
3008
    
3009
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3010
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3011
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3012
        return;
3013
    }
3014
    
3015
    rtp_c->state = HTTPSTATE_READY;
3016
    rtp_c->first_pts = AV_NOPTS_VALUE;
3017
    /* now everything is OK, so we can send the connection parameters */
3018
    rtsp_reply_header(c, RTSP_STATUS_OK);
3019
    /* session ID */
3020
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3021
    url_fprintf(c->pb, "\r\n");
3022
}
3023

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

    
3028
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3029
    if (!rtp_c) {
3030
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3031
        return;
3032
    }
3033
    
3034
    /* abort the session */
3035
    close_connection(rtp_c);
3036

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

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

    
3050

    
3051
/********************************************************************/
3052
/* RTP handling */
3053

    
3054
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
3055
                                       FFStream *stream, const char *session_id,
3056
                                       enum RTSPProtocol rtp_protocol)
3057
{
3058
    HTTPContext *c = NULL;
3059
    const char *proto_str;
3060
    
3061
    /* XXX: should output a warning page when coming
3062
       close to the connection limit */
3063
    if (nb_connections >= nb_max_connections)
3064
        goto fail;
3065
    
3066
    /* add a new connection */
3067
    c = av_mallocz(sizeof(HTTPContext));
3068
    if (!c)
3069
        goto fail;
3070
    
3071
    c->fd = -1;
3072
    c->poll_entry = NULL;
3073
    c->from_addr = *from_addr;
3074
    c->buffer_size = IOBUFFER_INIT_SIZE;
3075
    c->buffer = av_malloc(c->buffer_size);
3076
    if (!c->buffer)
3077
        goto fail;
3078
    nb_connections++;
3079
    c->stream = stream;
3080
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3081
    c->state = HTTPSTATE_READY;
3082
    c->is_packetized = 1;
3083
    c->rtp_protocol = rtp_protocol;
3084

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

    
3103
    current_bandwidth += stream->bandwidth;
3104

    
3105
    c->next = first_http_ctx;
3106
    first_http_ctx = c;
3107
    return c;
3108
        
3109
 fail:
3110
    if (c) {
3111
        av_free(c->buffer);
3112
        av_free(c);
3113
    }
3114
    return NULL;
3115
}
3116

    
3117
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3118
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3119
   used. */
3120
static int rtp_new_av_stream(HTTPContext *c, 
3121
                             int stream_index, struct sockaddr_in *dest_addr,
3122
                             HTTPContext *rtsp_c)
3123
{
3124
    AVFormatContext *ctx;
3125
    AVStream *st;
3126
    char *ipaddr;
3127
    URLContext *h;
3128
    uint8_t *dummy_buf;
3129
    char buf2[32];
3130
    int max_packet_size;
3131
    
3132
    /* now we can open the relevant output stream */
3133
    ctx = av_alloc_format_context();
3134
    if (!ctx)
3135
        return -1;
3136
    ctx->oformat = &rtp_mux;
3137

    
3138
    st = av_mallocz(sizeof(AVStream));
3139
    if (!st)
3140
        goto fail;
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->priv_data = av_mallocz(sizeof(FeedData));
3225
    memcpy(&fst->codec, codec, sizeof(AVCodecContext));
3226
    fst->codec.coded_frame = &dummy_frame;
3227
    fst->index = stream->nb_streams;
3228
    av_set_pts_info(fst, 33, 1, 90000);
3229
    stream->streams[stream->nb_streams++] = fst;
3230
    return fst;
3231
}
3232

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

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

    
3248
            switch(av->codec_type) {
3249
            case CODEC_TYPE_AUDIO:
3250
                if (av1->channels == av->channels &&
3251
                    av1->sample_rate == av->sample_rate)
3252
                    goto found;
3253
                break;
3254
            case CODEC_TYPE_VIDEO:
3255
                if (av1->width == av->width &&
3256
                    av1->height == av->height &&
3257
                    av1->frame_rate == av->frame_rate &&
3258
                    av1->frame_rate_base == av->frame_rate_base &&
3259
                    av1->gop_size == av->gop_size)
3260
                    goto found;
3261
                break;
3262
            default:
3263
                av_abort();
3264
            }
3265
        }
3266
    }
3267
    
3268
    fst = add_av_stream1(feed, av);
3269
    if (!fst)
3270
        return -1;
3271
    return feed->nb_streams - 1;
3272
 found:
3273
    return i;
3274
}
3275

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

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

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

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

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

    
3345
    /* gather all streams */
3346
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3347
        stream_next = stream->next;
3348
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3349
            !stream->feed) {
3350
            /* the stream comes from a file */
3351
            /* try to open the file */
3352
            /* open stream */
3353
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3354
            if (stream->fmt == &rtp_mux) {
3355
                /* specific case : if transport stream output to RTP,
3356
                   we use a raw transport stream reader */
3357
                stream->ap_in->mpeg2ts_raw = 1;
3358
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3359
            }
3360
            
3361
            if (av_open_input_file(&infile, stream->feed_filename, 
3362
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3363
                http_log("%s not found", stream->feed_filename);
3364
                /* remove stream (no need to spend more time on it) */
3365
            fail:
3366
                remove_stream(stream);
3367
            } else {
3368
                /* find all the AVStreams inside and reference them in
3369
                   'stream' */
3370
                if (av_find_stream_info(infile) < 0) {
3371
                    http_log("Could not find codec parameters from '%s'", 
3372
                             stream->feed_filename);
3373
                    av_close_input_file(infile);
3374
                    goto fail;
3375
                }
3376
                extract_mpeg4_header(infile);
3377

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3539
        close(fd);
3540
    }
3541
}
3542

    
3543
/* compute the bandwidth used by each stream */
3544
static void compute_bandwidth(void)
3545
{
3546
    int bandwidth, i;
3547
    FFStream *stream;
3548
    
3549
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3550
        bandwidth = 0;
3551
        for(i=0;i<stream->nb_streams;i++) {
3552
            AVStream *st = stream->streams[i];
3553
            switch(st->codec.codec_type) {
3554
            case CODEC_TYPE_AUDIO:
3555
            case CODEC_TYPE_VIDEO:
3556
                bandwidth += st->codec.bit_rate;
3557
                break;
3558
            default:
3559
                break;
3560
            }
3561
        }
3562
        stream->bandwidth = (bandwidth + 999) / 1000;
3563
    }
3564
}
3565

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

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

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

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

    
3636
        if (!av->rc_eq)
3637
            av->rc_eq = "tex^qComp";
3638
        if (!av->i_quant_factor)
3639
            av->i_quant_factor = -0.8;
3640
        if (!av->b_quant_factor)
3641
            av->b_quant_factor = 1.25;
3642
        if (!av->b_quant_offset)
3643
            av->b_quant_offset = 1.25;
3644
        if (!av->rc_max_rate)
3645
            av->rc_max_rate = av->bit_rate * 2;
3646

    
3647
        break;
3648
    default:
3649
        av_abort();
3650
    }
3651

    
3652
    st = av_mallocz(sizeof(AVStream));
3653
    if (!st)
3654
        return;
3655
    stream->streams[stream->nb_streams++] = st;
3656
    memcpy(&st->codec, av, sizeof(AVCodecContext));
3657
}
3658

    
3659
static int opt_audio_codec(const char *arg)
3660
{
3661
    AVCodec *p;
3662

    
3663
    p = first_avcodec;
3664
    while (p) {
3665
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3666
            break;
3667
        p = p->next;
3668
    }
3669
    if (p == NULL) {
3670
        return CODEC_ID_NONE;
3671
    }
3672

    
3673
    return p->id;
3674
}
3675

    
3676
static int opt_video_codec(const char *arg)
3677
{
3678
    AVCodec *p;
3679

    
3680
    p = first_avcodec;
3681
    while (p) {
3682
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3683
            break;
3684
        p = p->next;
3685
    }
3686
    if (p == NULL) {
3687
        return CODEC_ID_NONE;
3688
    }
3689

    
3690
    return p->id;
3691
}
3692

    
3693
/* simplistic plugin support */
3694

    
3695
#ifdef CONFIG_HAVE_DLOPEN
3696
void load_module(const char *filename)
3697
{
3698
    void *dll;
3699
    void (*init_func)(void);
3700
    dll = dlopen(filename, RTLD_NOW);
3701
    if (!dll) {
3702
        fprintf(stderr, "Could not load module '%s' - %s\n",
3703
                filename, dlerror());
3704
        return;
3705
    }
3706
    
3707
    init_func = dlsym(dll, "ffserver_module_init");
3708
    if (!init_func) {
3709
        fprintf(stderr, 
3710
                "%s: init function 'ffserver_module_init()' not found\n",
3711
                filename);
3712
        dlclose(dll);
3713
    }
3714

    
3715
    init_func();
3716
}
3717
#endif
3718

    
3719
static int parse_ffconfig(const char *filename)
3720
{
3721
    FILE *f;
3722
    char line[1024];
3723
    char cmd[64];
3724
    char arg[1024];
3725
    const char *p;
3726
    int val, errors, line_num;
3727
    FFStream **last_stream, *stream, *redirect;
3728
    FFStream **last_feed, *feed;
3729
    AVCodecContext audio_enc, video_enc;
3730
    int audio_id, video_id;
3731

    
3732
    f = fopen(filename, "r");
3733
    if (!f) {
3734
        perror(filename);
3735
        return -1;
3736
    }
3737
    
3738
    errors = 0;
3739
    line_num = 0;
3740
    first_stream = NULL;
3741
    last_stream = &first_stream;
3742
    first_feed = NULL;
3743
    last_feed = &first_feed;
3744
    stream = NULL;
3745
    feed = NULL;
3746
    redirect = NULL;
3747
    audio_id = CODEC_ID_NONE;
3748
    video_id = CODEC_ID_NONE;
3749
    for(;;) {
3750
        if (fgets(line, sizeof(line), f) == NULL)
3751
            break;
3752
        line_num++;
3753
        p = line;
3754
        while (isspace(*p)) 
3755
            p++;
3756
        if (*p == '\0' || *p == '#')
3757
            continue;
3758

    
3759
        get_arg(cmd, sizeof(cmd), &p);
3760
        
3761
        if (!strcasecmp(cmd, "Port")) {
3762
            get_arg(arg, sizeof(arg), &p);
3763
            my_http_addr.sin_port = htons (atoi(arg));
3764
        } else if (!strcasecmp(cmd, "BindAddress")) {
3765
            get_arg(arg, sizeof(arg), &p);
3766
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3767
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3768
                        filename, line_num, arg);
3769
                errors++;
3770
            }
3771
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3772
            ffserver_daemon = 0;
3773
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3774
            get_arg(arg, sizeof(arg), &p);
3775
            my_rtsp_addr.sin_port = htons (atoi(arg));
3776
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3777
            get_arg(arg, sizeof(arg), &p);
3778
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3779
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3780
                        filename, line_num, arg);
3781
                errors++;
3782
            }
3783
        } else if (!strcasecmp(cmd, "MaxClients")) {
3784
            get_arg(arg, sizeof(arg), &p);
3785
            val = atoi(arg);
3786
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3787
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3788
                        filename, line_num, arg);
3789
                errors++;
3790
            } else {
3791
                nb_max_connections = val;
3792
            }
3793
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3794
            get_arg(arg, sizeof(arg), &p);
3795
            val = atoi(arg);
3796
            if (val < 10 || val > 100000) {
3797
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3798
                        filename, line_num, arg);
3799
                errors++;
3800
            } else {
3801
                max_bandwidth = val;
3802
            }
3803
        } else if (!strcasecmp(cmd, "CustomLog")) {
3804
            get_arg(logfilename, sizeof(logfilename), &p);
3805
        } else if (!strcasecmp(cmd, "<Feed")) {
3806
            /*********************************************/
3807
            /* Feed related options */
3808
            char *q;
3809
            if (stream || feed) {
3810
                fprintf(stderr, "%s:%d: Already in a tag\n",
3811
                        filename, line_num);
3812
            } else {
3813
                feed = av_mallocz(sizeof(FFStream));
3814
                /* add in stream list */
3815
                *last_stream = feed;
3816
                last_stream = &feed->next;
3817
                /* add in feed list */
3818
                *last_feed = feed;
3819
                last_feed = &feed->next_feed;
3820
                
3821
                get_arg(feed->filename, sizeof(feed->filename), &p);
3822
                q = strrchr(feed->filename, '>');
3823
                if (*q)
3824
                    *q = '\0';
3825
                feed->fmt = guess_format("ffm", NULL, NULL);
3826
                /* defaut feed file */
3827
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3828
                         "/tmp/%s.ffm", feed->filename);
3829
                feed->feed_max_size = 5 * 1024 * 1024;
3830
                feed->is_feed = 1;
3831
                feed->feed = feed; /* self feeding :-) */
3832
            }
3833
        } else if (!strcasecmp(cmd, "Launch")) {
3834
            if (feed) {
3835
                int i;
3836

    
3837
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3838

    
3839
                feed->child_argv[0] = av_malloc(7);
3840
                strcpy(feed->child_argv[0], "ffmpeg");
3841

    
3842
                for (i = 1; i < 62; i++) {
3843
                    char argbuf[256];
3844

    
3845
                    get_arg(argbuf, sizeof(argbuf), &p);
3846
                    if (!argbuf[0])
3847
                        break;
3848

    
3849
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3850
                    strcpy(feed->child_argv[i], argbuf);
3851
                }
3852

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

    
3855
                snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3856
                    ntohs(my_http_addr.sin_port), feed->filename);
3857
            }
3858
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3859
            if (feed) {
3860
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3861
                feed->readonly = 1;
3862
            } else if (stream) {
3863
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3864
            }
3865
        } else if (!strcasecmp(cmd, "File")) {
3866
            if (feed) {
3867
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3868
            } else if (stream) {
3869
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3870
            }
3871
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3872
            if (feed) {
3873
                const char *p1;
3874
                double fsize;
3875

    
3876
                get_arg(arg, sizeof(arg), &p);
3877
                p1 = arg;
3878
                fsize = strtod(p1, (char **)&p1);
3879
                switch(toupper(*p1)) {
3880
                case 'K':
3881
                    fsize *= 1024;
3882
                    break;
3883
                case 'M':
3884
                    fsize *= 1024 * 1024;
3885
                    break;
3886
                case 'G':
3887
                    fsize *= 1024 * 1024 * 1024;
3888
                    break;
3889
                }
3890
                feed->feed_max_size = (int64_t)fsize;
3891
            }
3892
        } else if (!strcasecmp(cmd, "</Feed>")) {
3893
            if (!feed) {
3894
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3895
                        filename, line_num);
3896
                errors++;
3897
#if 0
3898
            } else {
3899
                /* Make sure that we start out clean */
3900
                if (unlink(feed->feed_filename) < 0 
3901
                    && errno != ENOENT) {
3902
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3903
                        filename, line_num, feed->feed_filename, strerror(errno));
3904
                    errors++;
3905
                }
3906
#endif
3907
            }
3908
            feed = NULL;
3909
        } else if (!strcasecmp(cmd, "<Stream")) {
3910
            /*********************************************/
3911
            /* Stream related options */
3912
            char *q;
3913
            if (stream || feed) {
3914
                fprintf(stderr, "%s:%d: Already in a tag\n",
3915
                        filename, line_num);
3916
            } else {
3917
                stream = av_mallocz(sizeof(FFStream));
3918
                *last_stream = stream;
3919
                last_stream = &stream->next;
3920

    
3921
                get_arg(stream->filename, sizeof(stream->filename), &p);
3922
                q = strrchr(stream->filename, '>');
3923
                if (*q)
3924
                    *q = '\0';
3925
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3926
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3927
                memset(&video_enc, 0, sizeof(AVCodecContext));
3928
                audio_id = CODEC_ID_NONE;
3929
                video_id = CODEC_ID_NONE;
3930
                if (stream->fmt) {
3931
                    audio_id = stream->fmt->audio_codec;
3932
                    video_id = stream->fmt->video_codec;
3933
                }
3934
            }
3935
        } else if (!strcasecmp(cmd, "Feed")) {
3936
            get_arg(arg, sizeof(arg), &p);
3937
            if (stream) {
3938
                FFStream *sfeed;
3939
                
3940
                sfeed = first_feed;
3941
                while (sfeed != NULL) {
3942
                    if (!strcmp(sfeed->filename, arg))
3943
                        break;
3944
                    sfeed = sfeed->next_feed;
3945
                }
3946
                if (!sfeed) {
3947
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3948
                            filename, line_num, arg);
3949
                } else {
3950
                    stream->feed = sfeed;
3951
                }
3952
            }
3953
        } else if (!strcasecmp(cmd, "Format")) {
3954
            get_arg(arg, sizeof(arg), &p);
3955
            if (!strcmp(arg, "status")) {
3956
                stream->stream_type = STREAM_TYPE_STATUS;
3957
                stream->fmt = NULL;
3958
            } else {
3959
                stream->stream_type = STREAM_TYPE_LIVE;
3960
                /* jpeg cannot be used here, so use single frame jpeg */
3961
                if (!strcmp(arg, "jpeg"))
3962
                    strcpy(arg, "singlejpeg");
3963
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3964
                if (!stream->fmt) {
3965
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
3966
                            filename, line_num, arg);
3967
                    errors++;
3968
                }
3969
            }
3970
            if (stream->fmt) {
3971
                audio_id = stream->fmt->audio_codec;
3972
                video_id = stream->fmt->video_codec;
3973
            }
3974
        } else if (!strcasecmp(cmd, "InputFormat")) {
3975
            stream->ifmt = av_find_input_format(arg);
3976
            if (!stream->ifmt) {
3977
                fprintf(stderr, "%s:%d: Unknown input format: %s\n", 
3978
                        filename, line_num, arg);
3979
            }
3980
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3981
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3982
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3983
            } else {
3984
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
3985
                            filename, line_num);
3986
                errors++;
3987
            }
3988
        } else if (!strcasecmp(cmd, "Author")) {
3989
            if (stream) {
3990
                get_arg(stream->author, sizeof(stream->author), &p);
3991
            }
3992
        } else if (!strcasecmp(cmd, "Comment")) {
3993
            if (stream) {
3994
                get_arg(stream->comment, sizeof(stream->comment), &p);
3995
            }
3996
        } else if (!strcasecmp(cmd, "Copyright")) {
3997
            if (stream) {
3998
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
3999
            }
4000
        } else if (!strcasecmp(cmd, "Title")) {
4001
            if (stream) {
4002
                get_arg(stream->title, sizeof(stream->title), &p);
4003
            }
4004
        } else if (!strcasecmp(cmd, "Preroll")) {
4005
            get_arg(arg, sizeof(arg), &p);
4006
            if (stream) {
4007
                stream->prebuffer = atof(arg) * 1000;
4008
            }
4009
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4010
            if (stream) {
4011
                stream->send_on_key = 1;
4012
            }
4013
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4014
            get_arg(arg, sizeof(arg), &p);
4015
            audio_id = opt_audio_codec(arg);
4016
            if (audio_id == CODEC_ID_NONE) {
4017
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
4018
                        filename, line_num, arg);
4019
                errors++;
4020
            }
4021
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4022
            get_arg(arg, sizeof(arg), &p);
4023
            video_id = opt_video_codec(arg);
4024
            if (video_id == CODEC_ID_NONE) {
4025
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
4026
                        filename, line_num, arg);
4027
                errors++;
4028
            }
4029
        } else if (!strcasecmp(cmd, "MaxTime")) {
4030
            get_arg(arg, sizeof(arg), &p);
4031
            if (stream) {
4032
                stream->max_time = atof(arg) * 1000;
4033
            }
4034
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4035
            get_arg(arg, sizeof(arg), &p);
4036
            if (stream) {
4037
                audio_enc.bit_rate = atoi(arg) * 1000;
4038
            }
4039
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4040
            get_arg(arg, sizeof(arg), &p);
4041
            if (stream) {
4042
                audio_enc.channels = atoi(arg);
4043
            }
4044
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4045
            get_arg(arg, sizeof(arg), &p);
4046
            if (stream) {
4047
                audio_enc.sample_rate = atoi(arg);
4048
            }
4049
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4050
            get_arg(arg, sizeof(arg), &p);
4051
            if (stream) {
4052
//                audio_enc.quality = atof(arg) * 1000;
4053
            }
4054
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4055
            if (stream) {
4056
                int minrate, maxrate;
4057

    
4058
                get_arg(arg, sizeof(arg), &p);
4059

    
4060
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4061
                    video_enc.rc_min_rate = minrate * 1000;
4062
                    video_enc.rc_max_rate = maxrate * 1000;
4063
                } else {
4064
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
4065
                            filename, line_num, arg);
4066
                    errors++;
4067
                }
4068
            }
4069
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4070
            if (stream) {
4071
                get_arg(arg, sizeof(arg), &p);
4072
                video_enc.rc_buffer_size = atoi(arg) * 1024;
4073
            }
4074
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4075
            if (stream) {
4076
                get_arg(arg, sizeof(arg), &p);
4077
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4078
            }
4079
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4080
            get_arg(arg, sizeof(arg), &p);
4081
            if (stream) {
4082
                video_enc.bit_rate = atoi(arg) * 1000;
4083
            }
4084
        } else if (!strcasecmp(cmd, "VideoSize")) {
4085
            get_arg(arg, sizeof(arg), &p);
4086
            if (stream) {
4087
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4088
                if ((video_enc.width % 16) != 0 ||
4089
                    (video_enc.height % 16) != 0) {
4090
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4091
                            filename, line_num);
4092
                    errors++;
4093
                }
4094
            }
4095
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4096
            get_arg(arg, sizeof(arg), &p);
4097
            if (stream) {
4098
                video_enc.frame_rate_base= DEFAULT_FRAME_RATE_BASE;
4099
                video_enc.frame_rate = (int)(strtod(arg, NULL) * video_enc.frame_rate_base);
4100
            }
4101
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4102
            get_arg(arg, sizeof(arg), &p);
4103
            if (stream) {
4104
                video_enc.gop_size = atoi(arg);
4105
            }
4106
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4107
            if (stream) {
4108
                video_enc.gop_size = 1;
4109
            }
4110
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4111
            if (stream) {
4112
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4113
            }
4114
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4115
            if (stream) {
4116
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4117
                video_enc.flags |= CODEC_FLAG_4MV;
4118
            }
4119
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4120
            get_arg(arg, sizeof(arg), &p);
4121
            if (stream) {
4122
                video_enc.max_qdiff = atoi(arg);
4123
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4124
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4125
                            filename, line_num);
4126
                    errors++;
4127
                }
4128
            }
4129
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4130
            get_arg(arg, sizeof(arg), &p);
4131
            if (stream) {
4132
                video_enc.qmax = atoi(arg);
4133
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4134
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4135
                            filename, line_num);
4136
                    errors++;
4137
                }
4138
            }
4139
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4140
            get_arg(arg, sizeof(arg), &p);
4141
            if (stream) {
4142
                video_enc.qmin = atoi(arg);
4143
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4144
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4145
                            filename, line_num);
4146
                    errors++;
4147
                }
4148
            }
4149
        } else if (!strcasecmp(cmd, "LumaElim")) {
4150
            get_arg(arg, sizeof(arg), &p);
4151
            if (stream) {
4152
                video_enc.luma_elim_threshold = atoi(arg);
4153
            }
4154
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4155
            get_arg(arg, sizeof(arg), &p);
4156
            if (stream) {
4157
                video_enc.chroma_elim_threshold = atoi(arg);
4158
            }
4159
        } else if (!strcasecmp(cmd, "LumiMask")) {
4160
            get_arg(arg, sizeof(arg), &p);
4161
            if (stream) {
4162
                video_enc.lumi_masking = atof(arg);
4163
            }
4164
        } else if (!strcasecmp(cmd, "DarkMask")) {
4165
            get_arg(arg, sizeof(arg), &p);
4166
            if (stream) {
4167
                video_enc.dark_masking = atof(arg);
4168
            }
4169
        } else if (!strcasecmp(cmd, "NoVideo")) {
4170
            video_id = CODEC_ID_NONE;
4171
        } else if (!strcasecmp(cmd, "NoAudio")) {
4172
            audio_id = CODEC_ID_NONE;
4173
        } else if (!strcasecmp(cmd, "ACL")) {
4174
            IPAddressACL acl;
4175
            struct hostent *he;
4176

    
4177
            get_arg(arg, sizeof(arg), &p);
4178
            if (strcasecmp(arg, "allow") == 0) {
4179
                acl.action = IP_ALLOW;
4180
            } else if (strcasecmp(arg, "deny") == 0) {
4181
                acl.action = IP_DENY;
4182
            } else {
4183
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4184
                        filename, line_num, arg);
4185
                errors++;
4186
            }
4187

    
4188
            get_arg(arg, sizeof(arg), &p);
4189

    
4190
            he = gethostbyname(arg);
4191
            if (!he) {
4192
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4193
                        filename, line_num, arg);
4194
                errors++;
4195
            } else {
4196
                /* Only take the first */
4197
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4198
                acl.last = acl.first;
4199
            }
4200

    
4201
            get_arg(arg, sizeof(arg), &p);
4202

    
4203
            if (arg[0]) {
4204
                he = gethostbyname(arg);
4205
                if (!he) {
4206
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4207
                            filename, line_num, arg);
4208
                    errors++;
4209
                } else {
4210
                    /* Only take the first */
4211
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4212
                }
4213
            }
4214

    
4215
            if (!errors) {
4216
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4217
                IPAddressACL **naclp = 0;
4218

    
4219
                *nacl = acl;
4220
                nacl->next = 0;
4221

    
4222
                if (stream) {
4223
                    naclp = &stream->acl;
4224
                } else if (feed) {
4225
                    naclp = &feed->acl;
4226
                } else {
4227
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4228
                            filename, line_num);
4229
                    errors++;
4230
                }
4231

    
4232
                if (naclp) {
4233
                    while (*naclp)
4234
                        naclp = &(*naclp)->next;
4235

    
4236
                    *naclp = nacl;
4237
                }
4238
            }
4239
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4240
            get_arg(arg, sizeof(arg), &p);
4241
            if (stream) {
4242
                av_freep(&stream->rtsp_option);
4243
                /* XXX: av_strdup ? */
4244
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4245
                if (stream->rtsp_option) {
4246
                    strcpy(stream->rtsp_option, arg);
4247
                }
4248
            }
4249
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4250
            get_arg(arg, sizeof(arg), &p);
4251
            if (stream) {
4252
                if (!inet_aton(arg, &stream->multicast_ip)) {
4253
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
4254
                            filename, line_num, arg);
4255
                    errors++;
4256
                }
4257
                stream->is_multicast = 1;
4258
                stream->loop = 1; /* default is looping */
4259
            }
4260
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4261
            get_arg(arg, sizeof(arg), &p);
4262
            if (stream) {
4263
                stream->multicast_port = atoi(arg);
4264
            }
4265
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4266
            get_arg(arg, sizeof(arg), &p);
4267
            if (stream) {
4268
                stream->multicast_ttl = atoi(arg);
4269
            }
4270
        } else if (!strcasecmp(cmd, "NoLoop")) {
4271
            if (stream) {
4272
                stream->loop = 0;
4273
            }
4274
        } else if (!strcasecmp(cmd, "</Stream>")) {
4275
            if (!stream) {
4276
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4277
                        filename, line_num);
4278
                errors++;
4279
            }
4280
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4281
                if (audio_id != CODEC_ID_NONE) {
4282
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4283
                    audio_enc.codec_id = audio_id;
4284
                    add_codec(stream, &audio_enc);
4285
                }
4286
                if (video_id != CODEC_ID_NONE) {
4287
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4288
                    video_enc.codec_id = video_id;
4289
                    if (!video_enc.rc_buffer_size) {
4290
                        video_enc.rc_buffer_size = 40 * 1024;
4291
                    }
4292
                    add_codec(stream, &video_enc);
4293
                }
4294
            }
4295
            stream = NULL;
4296
        } else if (!strcasecmp(cmd, "<Redirect")) {
4297
            /*********************************************/
4298
            char *q;
4299
            if (stream || feed || redirect) {
4300
                fprintf(stderr, "%s:%d: Already in a tag\n",
4301
                        filename, line_num);
4302
                errors++;
4303
            } else {
4304
                redirect = av_mallocz(sizeof(FFStream));
4305
                *last_stream = redirect;
4306
                last_stream = &redirect->next;
4307

    
4308
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4309
                q = strrchr(redirect->filename, '>');
4310
                if (*q)
4311
                    *q = '\0';
4312
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4313
            }
4314
        } else if (!strcasecmp(cmd, "URL")) {
4315
            if (redirect) {
4316
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4317
            }
4318
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4319
            if (!redirect) {
4320
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4321
                        filename, line_num);
4322
                errors++;
4323
            }
4324
            if (!redirect->feed_filename[0]) {
4325
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4326
                        filename, line_num);
4327
                errors++;
4328
            }
4329
            redirect = NULL;
4330
        } else if (!strcasecmp(cmd, "LoadModule")) {
4331
            get_arg(arg, sizeof(arg), &p);
4332
#ifdef CONFIG_HAVE_DLOPEN
4333
            load_module(arg);
4334
#else
4335
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n", 
4336
                    filename, line_num, arg);
4337
            errors++;
4338
#endif
4339
        } else {
4340
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
4341
                    filename, line_num, cmd);
4342
            errors++;
4343
        }
4344
    }
4345

    
4346
    fclose(f);
4347
    if (errors)
4348
        return -1;
4349
    else
4350
        return 0;
4351
}
4352

    
4353

    
4354
#if 0
4355
static void write_packet(FFCodec *ffenc,
4356
                         uint8_t *buf, int size)
4357
{
4358
    PacketHeader hdr;
4359
    AVCodecContext *enc = &ffenc->enc;
4360
    uint8_t *wptr;
4361
    mk_header(&hdr, enc, size);
4362
    wptr = http_fifo.wptr;
4363
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4364
    fifo_write(&http_fifo, buf, size, &wptr);
4365
    /* atomic modification of wptr */
4366
    http_fifo.wptr = wptr;
4367
    ffenc->data_count += size;
4368
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4369
}
4370
#endif
4371

    
4372
static void show_banner(void)
4373
{
4374
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4375
}
4376

    
4377
static void show_help(void)
4378
{
4379
    show_banner();
4380
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4381
           "Hyper fast multi format Audio/Video streaming server\n"
4382
           "\n"
4383
           "-L            : print the LICENSE\n"
4384
           "-h            : this help\n"
4385
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4386
           );
4387
}
4388

    
4389
static void show_license(void)
4390
{
4391
    show_banner();
4392
    printf(
4393
    "This library is free software; you can redistribute it and/or\n"
4394
    "modify it under the terms of the GNU Lesser General Public\n"
4395
    "License as published by the Free Software Foundation; either\n"
4396
    "version 2 of the License, or (at your option) any later version.\n"
4397
    "\n"
4398
    "This library is distributed in the hope that it will be useful,\n"
4399
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4400
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4401
    "Lesser General Public License for more details.\n"
4402
    "\n"
4403
    "You should have received a copy of the GNU Lesser General Public\n"
4404
    "License along with this library; if not, write to the Free Software\n"
4405
    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4406
    );
4407
}
4408

    
4409
static void handle_child_exit(int sig)
4410
{
4411
    pid_t pid;
4412
    int status;
4413

    
4414
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4415
        FFStream *feed;
4416

    
4417
        for (feed = first_feed; feed; feed = feed->next) {
4418
            if (feed->pid == pid) {
4419
                int uptime = time(0) - feed->pid_start;
4420

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

    
4424
                if (uptime < 30) {
4425
                    /* Turn off any more restarts */
4426
                    feed->child_argv = 0;
4427
                }    
4428
            }
4429
        }
4430
    }
4431

    
4432
    need_to_start_children = 1;
4433
}
4434

    
4435
int main(int argc, char **argv)
4436
{
4437
    const char *config_filename;
4438
    int c;
4439
    struct sigaction sigact;
4440

    
4441
    av_register_all();
4442

    
4443
    config_filename = "/etc/ffserver.conf";
4444

    
4445
    my_program_name = argv[0];
4446
    my_program_dir = getcwd(0, 0);
4447
    ffserver_daemon = 1;
4448
    
4449
    for(;;) {
4450
        c = getopt(argc, argv, "ndLh?f:");
4451
        if (c == -1)
4452
            break;
4453
        switch(c) {
4454
        case 'L':
4455
            show_license();
4456
            exit(1);
4457
        case '?':
4458
        case 'h':
4459
            show_help();
4460
            exit(1);
4461
        case 'n':
4462
            no_launch = 1;
4463
            break;
4464
        case 'd':
4465
            ffserver_debug = 1;
4466
            ffserver_daemon = 0;
4467
            break;
4468
        case 'f':
4469
            config_filename = optarg;
4470
            break;
4471
        default:
4472
            exit(2);
4473
        }
4474
    }
4475

    
4476
    putenv("http_proxy");               /* Kill the http_proxy */
4477

    
4478
    srandom(gettime_ms() + (getpid() << 16));
4479

    
4480
    /* address on which the server will handle HTTP connections */
4481
    my_http_addr.sin_family = AF_INET;
4482
    my_http_addr.sin_port = htons (8080);
4483
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4484

    
4485
    /* address on which the server will handle RTSP connections */
4486
    my_rtsp_addr.sin_family = AF_INET;
4487
    my_rtsp_addr.sin_port = htons (5454);
4488
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4489
    
4490
    nb_max_connections = 5;
4491
    max_bandwidth = 1000;
4492
    first_stream = NULL;
4493
    logfilename[0] = '\0';
4494

    
4495
    memset(&sigact, 0, sizeof(sigact));
4496
    sigact.sa_handler = handle_child_exit;
4497
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4498
    sigaction(SIGCHLD, &sigact, 0);
4499

    
4500
    if (parse_ffconfig(config_filename) < 0) {
4501
        fprintf(stderr, "Incorrect config file - exiting.\n");
4502
        exit(1);
4503
    }
4504

    
4505
    build_file_streams();
4506

    
4507
    build_feed_streams();
4508

    
4509
    compute_bandwidth();
4510

    
4511
    /* put the process in background and detach it from its TTY */
4512
    if (ffserver_daemon) {
4513
        int pid;
4514

    
4515
        pid = fork();
4516
        if (pid < 0) {
4517
            perror("fork");
4518
            exit(1);
4519
        } else if (pid > 0) {
4520
            /* parent : exit */
4521
            exit(0);
4522
        } else {
4523
            /* child */
4524
            setsid();
4525
            chdir("/");
4526
            close(0);
4527
            open("/dev/null", O_RDWR);
4528
            if (strcmp(logfilename, "-") != 0) {
4529
                close(1);
4530
                dup(0);
4531
            }
4532
            close(2);
4533
            dup(0);
4534
        }
4535
    }
4536

    
4537
    /* signal init */
4538
    signal(SIGPIPE, SIG_IGN);
4539

    
4540
    /* open log file if needed */
4541
    if (logfilename[0] != '\0') {
4542
        if (!strcmp(logfilename, "-"))
4543
            logfile = stdout;
4544
        else
4545
            logfile = fopen(logfilename, "w");
4546
    }
4547

    
4548
    if (http_server() < 0) {
4549
        fprintf(stderr, "Could not start server\n");
4550
        exit(1);
4551
    }
4552

    
4553
    return 0;
4554
}