Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 8d931070

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

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

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

    
156
static AVFrame dummy_frame;
157

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

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

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

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

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

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

    
231
struct sockaddr_in my_http_addr;
232
struct sockaddr_in my_rtsp_addr;
233

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

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

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

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

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

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

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

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

    
280
int nb_max_connections;
281
int nb_connections;
282

    
283
int max_bandwidth;
284
int current_bandwidth;
285

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

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

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

    
296
static FILE *logfile = NULL;
297

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

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

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

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

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

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

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

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

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

    
369

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

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

    
379
            feed->pid = fork();
380

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

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

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

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

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

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

    
418
                signal(SIGPIPE, SIG_DFL);
419

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

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

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

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

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

    
457
    return server_fd;
458
}
459

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

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

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

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

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

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

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

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

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

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

    
532
    start_children(first_feed);
533

    
534
    first_http_ctx = NULL;
535
    nb_connections = 0;
536

    
537
    start_multicast();
538

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

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

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

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

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

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

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

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

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

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

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

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

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

    
689
    return;
690

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
965
                q += 20;
966

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

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

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

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

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

    
992
        p++;
993
    }
994

    
995
    return 0;
996
}
997

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

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

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

    
1014
        /* Potential stream */
1015

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

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

    
1033
    return best;
1034
}
1035

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

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

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

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

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

    
1071
    return action_required;
1072
}
1073

    
1074

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1230
        p++;
1231
    }
1232

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

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

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

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

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

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

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

    
1330
            p++;
1331
        }
1332

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

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

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

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

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

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

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

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

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

    
1438
    stream->conns_served++;
1439

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

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

    
1463
                p++;
1464
            }
1465

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

    
1469
                logline += 17;
1470

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

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

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

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

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

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

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

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

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

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

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

    
1541
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1542
    }
1543
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1544
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1545
    
1546
    /* prepare output buffer */
1547
    c->http_error = 0;
1548
    c->buffer_ptr = c->buffer;
1549
    c->buffer_end = q;
1550
    c->state = HTTPSTATE_SEND_HEADER;
1551
    return 0;
1552
 send_error:
1553
    c->http_error = 404;
1554
    q = c->buffer;
1555
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1556
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1557
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1558
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1559
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1560
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1561
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1562

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

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

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

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

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

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

    
1603
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1604
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1605
    url_fprintf(pb, "Pragma: no-cache\r\n");
1606
    url_fprintf(pb, "\r\n");
1607
    
1608
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1609
    if (c->stream->feed_filename) {
1610
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1611
    }
1612
    url_fprintf(pb, "</HEAD>\n<BODY>");
1613
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1614
    /* format status */
1615
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1616
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1617
    url_fprintf(pb, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n");
1618
    stream = first_stream;
1619
    while (stream != NULL) {
1620
        char sfilename[1024];
1621
        char *eosf;
1622

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

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

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

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

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

    
1741
                url_fprintf(pb, "<p>");
1742
            }
1743
            url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1744

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

    
1751
                parameters[0] = 0;
1752

    
1753
                switch(st->codec->codec_type) {
1754
                case CODEC_TYPE_AUDIO:
1755
                    type = "audio";
1756
                    break;
1757
                case CODEC_TYPE_VIDEO:
1758
                    type = "video";
1759
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1760
                                st->codec->qmin, st->codec->qmax, st->codec->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
                feed->child_argv[0] = av_malloc(7);
3856
                strcpy(feed->child_argv[0], "ffmpeg");
3857

    
3858
                for (i = 1; i < 62; i++) {
3859
                    char argbuf[256];
3860

    
3861
                    get_arg(argbuf, sizeof(argbuf), &p);
3862
                    if (!argbuf[0])
3863
                        break;
3864

    
3865
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3866
                    strcpy(feed->child_argv[i], argbuf);
3867
                }
3868

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

    
3871
                snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
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
}