Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 01f4895c

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
            c->fmt_ctx.streams[i] = st;
2004
            /* if file or feed, then just take streams from FFStream struct */
2005
            if (!c->stream->feed || 
2006
                c->stream->feed == c->stream)
2007
                src = c->stream->streams[i];
2008
            else
2009
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2010

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2932

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3050

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

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

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

    
3103
    current_bandwidth += stream->bandwidth;
3104

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3539
        close(fd);
3540
    }
3541
}
3542

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

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

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

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

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

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

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

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

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

    
3658

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

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

    
3671
static int opt_audio_codec(const char *arg)
3672
{
3673
    AVCodec *p;
3674

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

    
3685
    return p->id;
3686
}
3687

    
3688
static int opt_video_codec(const char *arg)
3689
{
3690
    AVCodec *p;
3691

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

    
3702
    return p->id;
3703
}
3704

    
3705
/* simplistic plugin support */
3706

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

    
3727
    init_func();
3728
}
3729
#endif
3730

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

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

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

    
3849
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3850

    
3851
                feed->child_argv[0] = av_malloc(7);
3852
                strcpy(feed->child_argv[0], "ffmpeg");
3853

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

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

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

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

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

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

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

    
4070
                get_arg(arg, sizeof(arg), &p);
4071

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

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

    
4210
            get_arg(arg, sizeof(arg), &p);
4211

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

    
4223
            get_arg(arg, sizeof(arg), &p);
4224

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

    
4237
            if (!errors) {
4238
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4239
                IPAddressACL **naclp = 0;
4240

    
4241
                *nacl = acl;
4242
                nacl->next = 0;
4243

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

    
4254
                if (naclp) {
4255
                    while (*naclp)
4256
                        naclp = &(*naclp)->next;
4257

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

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

    
4365
    fclose(f);
4366
    if (errors)
4367
        return -1;
4368
    else
4369
        return 0;
4370
}
4371

    
4372

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

    
4391
static void show_banner(void)
4392
{
4393
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4394
}
4395

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

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

    
4428
static void handle_child_exit(int sig)
4429
{
4430
    pid_t pid;
4431
    int status;
4432

    
4433
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4434
        FFStream *feed;
4435

    
4436
        for (feed = first_feed; feed; feed = feed->next) {
4437
            if (feed->pid == pid) {
4438
                int uptime = time(0) - feed->pid_start;
4439

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

    
4443
                if (uptime < 30) {
4444
                    /* Turn off any more restarts */
4445
                    feed->child_argv = 0;
4446
                }    
4447
            }
4448
        }
4449
    }
4450

    
4451
    need_to_start_children = 1;
4452
}
4453

    
4454
int main(int argc, char **argv)
4455
{
4456
    const char *config_filename;
4457
    int c;
4458
    struct sigaction sigact;
4459

    
4460
    av_register_all();
4461

    
4462
    config_filename = "/etc/ffserver.conf";
4463

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

    
4495
    putenv("http_proxy");               /* Kill the http_proxy */
4496

    
4497
    srandom(gettime_ms() + (getpid() << 16));
4498

    
4499
    /* address on which the server will handle HTTP connections */
4500
    my_http_addr.sin_family = AF_INET;
4501
    my_http_addr.sin_port = htons (8080);
4502
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4503

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

    
4514
    memset(&sigact, 0, sizeof(sigact));
4515
    sigact.sa_handler = handle_child_exit;
4516
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4517
    sigaction(SIGCHLD, &sigact, 0);
4518

    
4519
    if (parse_ffconfig(config_filename) < 0) {
4520
        fprintf(stderr, "Incorrect config file - exiting.\n");
4521
        exit(1);
4522
    }
4523

    
4524
    build_file_streams();
4525

    
4526
    build_feed_streams();
4527

    
4528
    compute_bandwidth();
4529

    
4530
    /* put the process in background and detach it from its TTY */
4531
    if (ffserver_daemon) {
4532
        int pid;
4533

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

    
4556
    /* signal init */
4557
    signal(SIGPIPE, SIG_IGN);
4558

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

    
4567
    if (http_server() < 0) {
4568
        fprintf(stderr, "Could not start server\n");
4569
        exit(1);
4570
    }
4571

    
4572
    return 0;
4573
}