Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ ac6a655b

History | View | Annotate | Download (150 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
    int post;
104
    struct HTTPContext *next;
105
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
106
    int64_t data_count;
107
    /* feed input */
108
    int feed_fd;
109
    /* input format handling */
110
    AVFormatContext *fmt_in;
111
    long start_time;            /* In milliseconds - this wraps fairly often */
112
    int64_t first_pts;            /* initial pts value */
113
    int64_t cur_pts;             /* current pts value from the stream in us */
114
    int64_t cur_frame_duration;  /* duration of the current frame in us */
115
    int cur_frame_bytes;       /* output frame size, needed to compute
116
                                  the time at which we send each
117
                                  packet */
118
    int pts_stream_index;        /* stream we choose as clock reference */
119
    int64_t cur_clock;           /* current clock reference value in us */
120
    /* output format handling */
121
    struct FFStream *stream;
122
    /* -1 is invalid stream */
123
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
124
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
125
    int switch_pending;
126
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
127
    int last_packet_sent; /* true if last data packet was sent */
128
    int suppress_log;
129
    DataRateData datarate;
130
    int wmp_client_id;
131
    char protocol[16];
132
    char method[16];
133
    char url[128];
134
    int buffer_size;
135
    uint8_t *buffer;
136
    int is_packetized; /* if true, the stream is packetized */
137
    int packet_stream_index; /* current stream for output in state machine */
138
    
139
    /* RTSP state specific */
140
    uint8_t *pb_buffer; /* XXX: use that in all the code */
141
    ByteIOContext *pb;
142
    int seq; /* RTSP sequence number */
143
    
144
    /* RTP state specific */
145
    enum RTSPProtocol rtp_protocol;
146
    char session_id[32]; /* session id */
147
    AVFormatContext *rtp_ctx[MAX_STREAMS];
148

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

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

    
157
static AVFrame dummy_frame;
158

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

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

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

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

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

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

    
232
struct sockaddr_in my_http_addr;
233
struct sockaddr_in my_rtsp_addr;
234

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

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

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

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

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

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

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

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

    
281
int nb_max_connections;
282
int nb_connections;
283

    
284
int max_bandwidth;
285
int current_bandwidth;
286

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

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

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

    
297
static FILE *logfile = NULL;
298

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

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

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

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

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

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

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

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

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

    
370

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

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

    
380
            feed->pid = fork();
381

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

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

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

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

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

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

    
419
                signal(SIGPIPE, SIG_DFL);
420

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

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

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

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

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

    
458
    return server_fd;
459
}
460

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

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

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

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

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

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

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

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

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

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

    
533
    start_children(first_feed);
534

    
535
    first_http_ctx = NULL;
536
    nb_connections = 0;
537

    
538
    start_multicast();
539

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

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

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

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

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

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

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

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

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

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

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

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

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

    
690
    return;
691

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
966
                q += 20;
967

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

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

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

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

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

    
993
        p++;
994
    }
995

    
996
    return 0;
997
}
998

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

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

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

    
1015
        /* Potential stream */
1016

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

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

    
1034
    return best;
1035
}
1036

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

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

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

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

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

    
1072
    return action_required;
1073
}
1074

    
1075

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

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

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

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

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

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

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

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

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

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

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

    
1170
/* parse http request and prepare header */
1171
static int http_parse_request(HTTPContext *c)
1172
{
1173
    char *p;
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
        c->post = 0;
1192
    else if (!strcmp(cmd, "POST"))
1193
        c->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 (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1296
        current_bandwidth += stream->bandwidth;
1297
    }
1298
    
1299
    if (c->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 (c->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->time_base.den / st->codec->time_base.num);
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 1
1944
    if (c->fmt_in->iformat->read_seek) {
1945
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
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
            st->codec= avcodec_alloc_context();
2004
            c->fmt_ctx.streams[i] = st;
2005
            /* if file or feed, then just take streams from FFStream struct */
2006
            if (!c->stream->feed || 
2007
                c->stream->feed == c->stream)
2008
                src = c->stream->streams[i];
2009
            else
2010
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2011

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2481
/********************************************************************/
2482
/* RTSP handling */
2483

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2933

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3051

    
3052
/********************************************************************/
3053
/* RTP handling */
3054

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

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

    
3104
    current_bandwidth += stream->bandwidth;
3105

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

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

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

    
3146
    if (!c->stream->feed || 
3147
        c->stream->feed == c->stream) {
3148
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3149
    } else {
3150
        memcpy(st, 
3151
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3152
               sizeof(AVStream));
3153
    }
3154
    
3155
    /* build destination RTP address */
3156
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3157

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

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

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

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

    
3216
/********************************************************************/
3217
/* ffserver initialization */
3218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3542
        close(fd);
3543
    }
3544
}
3545

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

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

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

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

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

    
3639
        if (!av->nsse_weight) 
3640
            av->nsse_weight = 8;
3641

    
3642
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3643
        av->me_method = ME_EPZS;
3644
        av->rc_buffer_aggressivity = 1.0;
3645

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

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

    
3661

    
3662
        break;
3663
    default:
3664
        av_abort();
3665
    }
3666

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

    
3675
static int opt_audio_codec(const char *arg)
3676
{
3677
    AVCodec *p;
3678

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

    
3689
    return p->id;
3690
}
3691

    
3692
static int opt_video_codec(const char *arg)
3693
{
3694
    AVCodec *p;
3695

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

    
3706
    return p->id;
3707
}
3708

    
3709
/* simplistic plugin support */
3710

    
3711
#ifdef CONFIG_HAVE_DLOPEN
3712
void load_module(const char *filename)
3713
{
3714
    void *dll;
3715
    void (*init_func)(void);
3716
    dll = dlopen(filename, RTLD_NOW);
3717
    if (!dll) {
3718
        fprintf(stderr, "Could not load module '%s' - %s\n",
3719
                filename, dlerror());
3720
        return;
3721
    }
3722
    
3723
    init_func = dlsym(dll, "ffserver_module_init");
3724
    if (!init_func) {
3725
        fprintf(stderr, 
3726
                "%s: init function 'ffserver_module_init()' not found\n",
3727
                filename);
3728
        dlclose(dll);
3729
    }
3730

    
3731
    init_func();
3732
}
3733
#endif
3734

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

    
3748
    f = fopen(filename, "r");
3749
    if (!f) {
3750
        perror(filename);
3751
        return -1;
3752
    }
3753
    
3754
    errors = 0;
3755
    line_num = 0;
3756
    first_stream = NULL;
3757
    last_stream = &first_stream;
3758
    first_feed = NULL;
3759
    last_feed = &first_feed;
3760
    stream = NULL;
3761
    feed = NULL;
3762
    redirect = NULL;
3763
    audio_id = CODEC_ID_NONE;
3764
    video_id = CODEC_ID_NONE;
3765
    for(;;) {
3766
        if (fgets(line, sizeof(line), f) == NULL)
3767
            break;
3768
        line_num++;
3769
        p = line;
3770
        while (isspace(*p)) 
3771
            p++;
3772
        if (*p == '\0' || *p == '#')
3773
            continue;
3774

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

    
3853
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3854

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

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

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

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

    
3868
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3869
                    "http://%s:%d/%s", 
3870
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3871
                    inet_ntoa(my_http_addr.sin_addr),
3872
                    ntohs(my_http_addr.sin_port), feed->filename);
3873
            }
3874
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3875
            if (feed) {
3876
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3877
                feed->readonly = 1;
3878
            } else if (stream) {
3879
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3880
            }
3881
        } else if (!strcasecmp(cmd, "File")) {
3882
            if (feed) {
3883
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3884
            } else if (stream) {
3885
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3886
            }
3887
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3888
            if (feed) {
3889
                const char *p1;
3890
                double fsize;
3891

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

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

    
4074
                get_arg(arg, sizeof(arg), &p);
4075

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

    
4203
            get_arg(arg, sizeof(arg), &p);
4204
            if (strcasecmp(arg, "allow") == 0) {
4205
                acl.action = IP_ALLOW;
4206
            } else if (strcasecmp(arg, "deny") == 0) {
4207
                acl.action = IP_DENY;
4208
            } else {
4209
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4210
                        filename, line_num, arg);
4211
                errors++;
4212
            }
4213

    
4214
            get_arg(arg, sizeof(arg), &p);
4215

    
4216
            he = gethostbyname(arg);
4217
            if (!he) {
4218
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4219
                        filename, line_num, arg);
4220
                errors++;
4221
            } else {
4222
                /* Only take the first */
4223
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4224
                acl.last = acl.first;
4225
            }
4226

    
4227
            get_arg(arg, sizeof(arg), &p);
4228

    
4229
            if (arg[0]) {
4230
                he = gethostbyname(arg);
4231
                if (!he) {
4232
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4233
                            filename, line_num, arg);
4234
                    errors++;
4235
                } else {
4236
                    /* Only take the first */
4237
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4238
                }
4239
            }
4240

    
4241
            if (!errors) {
4242
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4243
                IPAddressACL **naclp = 0;
4244

    
4245
                *nacl = acl;
4246
                nacl->next = 0;
4247

    
4248
                if (stream) {
4249
                    naclp = &stream->acl;
4250
                } else if (feed) {
4251
                    naclp = &feed->acl;
4252
                } else {
4253
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4254
                            filename, line_num);
4255
                    errors++;
4256
                }
4257

    
4258
                if (naclp) {
4259
                    while (*naclp)
4260
                        naclp = &(*naclp)->next;
4261

    
4262
                    *naclp = nacl;
4263
                }
4264
            }
4265
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4266
            get_arg(arg, sizeof(arg), &p);
4267
            if (stream) {
4268
                av_freep(&stream->rtsp_option);
4269
                /* XXX: av_strdup ? */
4270
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4271
                if (stream->rtsp_option) {
4272
                    strcpy(stream->rtsp_option, arg);
4273
                }
4274
            }
4275
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4276
            get_arg(arg, sizeof(arg), &p);
4277
            if (stream) {
4278
                if (!inet_aton(arg, &stream->multicast_ip)) {
4279
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
4280
                            filename, line_num, arg);
4281
                    errors++;
4282
                }
4283
                stream->is_multicast = 1;
4284
                stream->loop = 1; /* default is looping */
4285
            }
4286
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4287
            get_arg(arg, sizeof(arg), &p);
4288
            if (stream) {
4289
                stream->multicast_port = atoi(arg);
4290
            }
4291
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4292
            get_arg(arg, sizeof(arg), &p);
4293
            if (stream) {
4294
                stream->multicast_ttl = atoi(arg);
4295
            }
4296
        } else if (!strcasecmp(cmd, "NoLoop")) {
4297
            if (stream) {
4298
                stream->loop = 0;
4299
            }
4300
        } else if (!strcasecmp(cmd, "</Stream>")) {
4301
            if (!stream) {
4302
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4303
                        filename, line_num);
4304
                errors++;
4305
            }
4306
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4307
                if (audio_id != CODEC_ID_NONE) {
4308
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4309
                    audio_enc.codec_id = audio_id;
4310
                    add_codec(stream, &audio_enc);
4311
                }
4312
                if (video_id != CODEC_ID_NONE) {
4313
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4314
                    video_enc.codec_id = video_id;
4315
                    add_codec(stream, &video_enc);
4316
                }
4317
            }
4318
            stream = NULL;
4319
        } else if (!strcasecmp(cmd, "<Redirect")) {
4320
            /*********************************************/
4321
            char *q;
4322
            if (stream || feed || redirect) {
4323
                fprintf(stderr, "%s:%d: Already in a tag\n",
4324
                        filename, line_num);
4325
                errors++;
4326
            } else {
4327
                redirect = av_mallocz(sizeof(FFStream));
4328
                *last_stream = redirect;
4329
                last_stream = &redirect->next;
4330

    
4331
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4332
                q = strrchr(redirect->filename, '>');
4333
                if (*q)
4334
                    *q = '\0';
4335
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4336
            }
4337
        } else if (!strcasecmp(cmd, "URL")) {
4338
            if (redirect) {
4339
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4340
            }
4341
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4342
            if (!redirect) {
4343
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4344
                        filename, line_num);
4345
                errors++;
4346
            }
4347
            if (!redirect->feed_filename[0]) {
4348
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4349
                        filename, line_num);
4350
                errors++;
4351
            }
4352
            redirect = NULL;
4353
        } else if (!strcasecmp(cmd, "LoadModule")) {
4354
            get_arg(arg, sizeof(arg), &p);
4355
#ifdef CONFIG_HAVE_DLOPEN
4356
            load_module(arg);
4357
#else
4358
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n", 
4359
                    filename, line_num, arg);
4360
            errors++;
4361
#endif
4362
        } else {
4363
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
4364
                    filename, line_num, cmd);
4365
            errors++;
4366
        }
4367
    }
4368

    
4369
    fclose(f);
4370
    if (errors)
4371
        return -1;
4372
    else
4373
        return 0;
4374
}
4375

    
4376

    
4377
#if 0
4378
static void write_packet(FFCodec *ffenc,
4379
                         uint8_t *buf, int size)
4380
{
4381
    PacketHeader hdr;
4382
    AVCodecContext *enc = &ffenc->enc;
4383
    uint8_t *wptr;
4384
    mk_header(&hdr, enc, size);
4385
    wptr = http_fifo.wptr;
4386
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4387
    fifo_write(&http_fifo, buf, size, &wptr);
4388
    /* atomic modification of wptr */
4389
    http_fifo.wptr = wptr;
4390
    ffenc->data_count += size;
4391
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4392
}
4393
#endif
4394

    
4395
static void show_banner(void)
4396
{
4397
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4398
}
4399

    
4400
static void show_help(void)
4401
{
4402
    show_banner();
4403
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4404
           "Hyper fast multi format Audio/Video streaming server\n"
4405
           "\n"
4406
           "-L            : print the LICENSE\n"
4407
           "-h            : this help\n"
4408
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4409
           );
4410
}
4411

    
4412
static void show_license(void)
4413
{
4414
    show_banner();
4415
    printf(
4416
    "This library is free software; you can redistribute it and/or\n"
4417
    "modify it under the terms of the GNU Lesser General Public\n"
4418
    "License as published by the Free Software Foundation; either\n"
4419
    "version 2 of the License, or (at your option) any later version.\n"
4420
    "\n"
4421
    "This library is distributed in the hope that it will be useful,\n"
4422
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4423
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4424
    "Lesser General Public License for more details.\n"
4425
    "\n"
4426
    "You should have received a copy of the GNU Lesser General Public\n"
4427
    "License along with this library; if not, write to the Free Software\n"
4428
    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4429
    );
4430
}
4431

    
4432
static void handle_child_exit(int sig)
4433
{
4434
    pid_t pid;
4435
    int status;
4436

    
4437
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4438
        FFStream *feed;
4439

    
4440
        for (feed = first_feed; feed; feed = feed->next) {
4441
            if (feed->pid == pid) {
4442
                int uptime = time(0) - feed->pid_start;
4443

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

    
4447
                if (uptime < 30) {
4448
                    /* Turn off any more restarts */
4449
                    feed->child_argv = 0;
4450
                }    
4451
            }
4452
        }
4453
    }
4454

    
4455
    need_to_start_children = 1;
4456
}
4457

    
4458
int main(int argc, char **argv)
4459
{
4460
    const char *config_filename;
4461
    int c;
4462
    struct sigaction sigact;
4463

    
4464
    av_register_all();
4465

    
4466
    config_filename = "/etc/ffserver.conf";
4467

    
4468
    my_program_name = argv[0];
4469
    my_program_dir = getcwd(0, 0);
4470
    ffserver_daemon = 1;
4471
    
4472
    for(;;) {
4473
        c = getopt(argc, argv, "ndLh?f:");
4474
        if (c == -1)
4475
            break;
4476
        switch(c) {
4477
        case 'L':
4478
            show_license();
4479
            exit(1);
4480
        case '?':
4481
        case 'h':
4482
            show_help();
4483
            exit(1);
4484
        case 'n':
4485
            no_launch = 1;
4486
            break;
4487
        case 'd':
4488
            ffserver_debug = 1;
4489
            ffserver_daemon = 0;
4490
            break;
4491
        case 'f':
4492
            config_filename = optarg;
4493
            break;
4494
        default:
4495
            exit(2);
4496
        }
4497
    }
4498

    
4499
    putenv("http_proxy");               /* Kill the http_proxy */
4500

    
4501
    srandom(gettime_ms() + (getpid() << 16));
4502

    
4503
    /* address on which the server will handle HTTP connections */
4504
    my_http_addr.sin_family = AF_INET;
4505
    my_http_addr.sin_port = htons (8080);
4506
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4507

    
4508
    /* address on which the server will handle RTSP connections */
4509
    my_rtsp_addr.sin_family = AF_INET;
4510
    my_rtsp_addr.sin_port = htons (5454);
4511
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4512
    
4513
    nb_max_connections = 5;
4514
    max_bandwidth = 1000;
4515
    first_stream = NULL;
4516
    logfilename[0] = '\0';
4517

    
4518
    memset(&sigact, 0, sizeof(sigact));
4519
    sigact.sa_handler = handle_child_exit;
4520
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4521
    sigaction(SIGCHLD, &sigact, 0);
4522

    
4523
    if (parse_ffconfig(config_filename) < 0) {
4524
        fprintf(stderr, "Incorrect config file - exiting.\n");
4525
        exit(1);
4526
    }
4527

    
4528
    build_file_streams();
4529

    
4530
    build_feed_streams();
4531

    
4532
    compute_bandwidth();
4533

    
4534
    /* put the process in background and detach it from its TTY */
4535
    if (ffserver_daemon) {
4536
        int pid;
4537

    
4538
        pid = fork();
4539
        if (pid < 0) {
4540
            perror("fork");
4541
            exit(1);
4542
        } else if (pid > 0) {
4543
            /* parent : exit */
4544
            exit(0);
4545
        } else {
4546
            /* child */
4547
            setsid();
4548
            chdir("/");
4549
            close(0);
4550
            open("/dev/null", O_RDWR);
4551
            if (strcmp(logfilename, "-") != 0) {
4552
                close(1);
4553
                dup(0);
4554
            }
4555
            close(2);
4556
            dup(0);
4557
        }
4558
    }
4559

    
4560
    /* signal init */
4561
    signal(SIGPIPE, SIG_IGN);
4562

    
4563
    /* open log file if needed */
4564
    if (logfilename[0] != '\0') {
4565
        if (!strcmp(logfilename, "-"))
4566
            logfile = stdout;
4567
        else
4568
            logfile = fopen(logfilename, "w");
4569
    }
4570

    
4571
    if (http_server() < 0) {
4572
        fprintf(stderr, "Could not start server\n");
4573
        exit(1);
4574
    }
4575

    
4576
    return 0;
4577
}