Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3e66a740

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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "version.h"
43
#include "ffserver.h"
44

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

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

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

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

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

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

    
79
#define IOBUFFER_INIT_SIZE 8192
80

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

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

    
88
#define SYNC_TIMEOUT (10 * 1000)
89

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

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

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

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

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

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

    
158
static AVFrame dummy_frame;
159

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

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

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

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

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

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

    
233
struct sockaddr_in my_http_addr;
234
struct sockaddr_in my_rtsp_addr;
235

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

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

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

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

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

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

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

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

    
282
static int nb_max_connections;
283
static int nb_connections;
284

    
285
static int max_bandwidth;
286
static int current_bandwidth;
287

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

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

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

    
298
static FILE *logfile = NULL;
299

    
300
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
301
{
302
    va_list ap;
303
    va_start(ap, fmt);
304

    
305
    if (logfile) {
306
        vfprintf(logfile, fmt, ap);
307
        fflush(logfile);
308
    }
309
    va_end(ap);
310
}
311

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

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

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

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

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

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

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

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

    
363

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

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

    
373
            feed->pid = fork();
374

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

    
385
                for (i = 3; i < 256; i++) {
386
                    close(i);
387
                }
388

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

    
399
                pstrcpy(pathname, sizeof(pathname), my_program_name);
400

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

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

    
412
                signal(SIGPIPE, SIG_DFL);
413

    
414
                execvp(pathname, feed->child_argv);
415

    
416
                _exit(1);
417
            }
418
        }
419
    }
420
}
421

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

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

    
433
    tmp = 1;
434
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
435

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

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

    
451
    return server_fd;
452
}
453

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

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

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

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

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

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

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

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

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

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

    
524
    http_log("ffserver started.\n");
525

    
526
    start_children(first_feed);
527

    
528
    first_http_ctx = NULL;
529
    nb_connections = 0;
530

    
531
    start_multicast();
532

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

    
539
        poll_entry->fd = rtsp_server_fd;
540
        poll_entry->events = POLLIN;
541
        poll_entry++;
542

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

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

    
601
        cur_time = gettime_ms();
602

    
603
        if (need_to_start_children) {
604
            need_to_start_children = 0;
605
            start_children(first_feed);
606
        }
607

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

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

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

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

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

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

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

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

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

    
677
    c->next = first_http_ctx;
678
    first_http_ctx = c;
679
    nb_connections++;
680

    
681
    start_wait_request(c, is_rtsp);
682

    
683
    return;
684

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

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

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

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

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

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

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

    
749
    ctx = &c->fmt_ctx;
750

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

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

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

    
773
static int handle_connection(HTTPContext *c)
774
{
775
    int len, ret;
776

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

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

    
819
    case HTTPSTATE_SEND_HEADER:
820
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
821
            return -1;
822

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

    
851
    case HTTPSTATE_SEND_DATA:
852
    case HTTPSTATE_SEND_DATA_HEADER:
853
    case HTTPSTATE_SEND_DATA_TRAILER:
854
        /* for packetized output, we consider we can always write (the
855
           input streams sets the speed). It may be better to verify
856
           that we do not rely too much on the kernel queues */
857
        if (!c->is_packetized) {
858
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
859
                return -1;
860

    
861
            /* no need to read if no events */
862
            if (!(c->poll_entry->revents & POLLOUT))
863
                return 0;
864
        }
865
        if (http_send_data(c) < 0)
866
            return -1;
867
        break;
868
    case HTTPSTATE_RECEIVE_DATA:
869
        /* no need to read if no events */
870
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
871
            return -1;
872
        if (!(c->poll_entry->revents & POLLIN))
873
            return 0;
874
        if (http_receive_data(c) < 0)
875
            return -1;
876
        break;
877
    case HTTPSTATE_WAIT_FEED:
878
        /* no need to read if no events */
879
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
880
            return -1;
881

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

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

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

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

    
952
            while (*q && *q != '\n' && isspace(*q))
953
                q++;
954

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

    
959
                q += 20;
960

    
961
                memset(rates, 0xff, ratelen);
962

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

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

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

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

    
986
        p++;
987
    }
988

    
989
    return 0;
990
}
991

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

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

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

    
1008
        /* Potential stream */
1009

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

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

    
1027
    return best;
1028
}
1029

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

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

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

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

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

    
1065
    return action_required;
1066
}
1067

    
1068

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1197
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1198

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

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

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

    
1226
        p++;
1227
    }
1228

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

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

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

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

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

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

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

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

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

    
1314
    if (redir_type != REDIR_NONE) {
1315
        char *hostinfo = 0;
1316

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

    
1326
            p++;
1327
        }
1328

    
1329
        if (hostinfo) {
1330
            char *eoh;
1331
            char hostbuf[260];
1332

    
1333
            while (isspace(*hostinfo))
1334
                hostinfo++;
1335

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

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

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

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

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

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

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

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

    
1434
    stream->conns_served++;
1435

    
1436
    /* XXX: add there authenticate and IP match */
1437

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

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

    
1459
                p++;
1460
            }
1461

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

    
1465
                logline += 17;
1466

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

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

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

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

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

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

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

    
1514
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1515
        goto send_stats;
1516

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

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

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

    
1535
        c->wmp_client_id = random() & 0x7fffffff;
1536

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

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

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

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

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

    
1580
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1581
}
1582

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

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

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

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

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

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

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

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

    
1712
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1713
                {
1714
                    FILE *pid_stat;
1715
                    char ps_cmd[64];
1716

    
1717
                    /* This is somewhat linux specific I guess */
1718
                    snprintf(ps_cmd, sizeof(ps_cmd),
1719
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1720
                             stream->pid);
1721

    
1722
                    pid_stat = popen(ps_cmd, "r");
1723
                    if (pid_stat) {
1724
                        char cpuperc[10];
1725
                        char cpuused[64];
1726

    
1727
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1728
                                   cpuused) == 2) {
1729
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1730
                                         cpuperc, cpuused);
1731
                        }
1732
                        fclose(pid_stat);
1733
                    }
1734
                }
1735
#endif
1736

    
1737
                url_fprintf(pb, "<p>");
1738
            }
1739
            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");
1740

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

    
1747
                parameters[0] = 0;
1748

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

    
1766
        }
1767
        stream = stream->next;
1768
    }
1769

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1973

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

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

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

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

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

    
2026
        av_set_parameters(&c->fmt_ctx, NULL);
2027
        av_write_header(&c->fmt_ctx);
2028

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

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

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

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

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

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

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

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

    
2202
        c->last_packet_sent = 1;
2203
        break;
2204
    }
2205
    return 0;
2206
}
2207

    
2208
/* in bit/s */
2209
#define SHORT_TERM_BANDWIDTH 8000000
2210

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

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

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

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

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

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

    
2337
static int http_start_receive_data(HTTPContext *c)
2338
{
2339
    int fd;
2340

    
2341
    if (c->stream->feed_opened)
2342
        return -1;
2343

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

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

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

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

    
2365
static int http_receive_data(HTTPContext *c)
2366
{
2367
    HTTPContext *c1;
2368

    
2369
    if (c->buffer_end > c->buffer_ptr) {
2370
        int len;
2371

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

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

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

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

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

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

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

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

    
2433
            memset(&s, 0, sizeof(s));
2434

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

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

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

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

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

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

    
2477
/********************************************************************/
2478
/* RTSP handling */
2479

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

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

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

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

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

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

    
2526
    c->buffer_ptr[0] = '\0';
2527
    p = c->buffer;
2528

    
2529
    get_word(cmd, sizeof(cmd), &p);
2530
    get_word(url, sizeof(url), &p);
2531
    get_word(protocol, sizeof(protocol), &p);
2532

    
2533
    pstrcpy(c->method, sizeof(c->method), cmd);
2534
    pstrcpy(c->url, sizeof(c->url), url);
2535
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2536

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

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

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

    
2576
    /* handle sequence number */
2577
    c->seq = header->seq;
2578

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

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

    
2617
    if (url_open_dyn_buf(pb) < 0)
2618
        return -1;
2619

    
2620
    /* general media info */
2621

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

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

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

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

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

    
2732
 found:
2733
    /* prepare the media description in sdp format */
2734

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

    
2750
static HTTPContext *find_rtp_session(const char *session_id)
2751
{
2752
    HTTPContext *c;
2753

    
2754
    if (session_id[0] == '\0')
2755
        return NULL;
2756

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2925

    
2926
    url_fprintf(c->pb, "\r\n");
2927
}
2928

    
2929

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

    
2941
    rtp_c = find_rtp_session(session_id);
2942
    if (!rtp_c)
2943
        return NULL;
2944

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

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

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

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

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

    
2987
    rtp_c->state = HTTPSTATE_SEND_DATA;
2988

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

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

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

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

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

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

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

    
3031
    /* abort the session */
3032
    close_connection(rtp_c);
3033

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

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

    
3047

    
3048
/********************************************************************/
3049
/* RTP handling */
3050

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

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

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

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

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

    
3100
    current_bandwidth += stream->bandwidth;
3101

    
3102
    c->next = first_http_ctx;
3103
    first_http_ctx = c;
3104
    return c;
3105

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

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

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

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

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

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

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

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

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

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

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

    
3208
    c->rtp_ctx[stream_index] = ctx;
3209
    return 0;
3210
}
3211

    
3212
/********************************************************************/
3213
/* ffserver initialization */
3214

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3538
        close(fd);
3539
    }
3540
}
3541

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

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

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

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

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

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

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

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

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

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

    
3657

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

    
3663
    st = av_mallocz(sizeof(AVStream));
3664
    if (!st)
3665
        return;
3666
    st->codec = avcodec_alloc_context();
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
static 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
                for (i = 0; i < 62; i++) {
3852
                    char argbuf[256];
3853

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

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

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

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

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

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

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

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

    
4079
                get_arg(arg, sizeof(arg), &p);
4080

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

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

    
4237
            get_arg(arg, sizeof(arg), &p);
4238

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

    
4250
            get_arg(arg, sizeof(arg), &p);
4251

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

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

    
4268
                *nacl = acl;
4269
                nacl->next = 0;
4270

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

    
4281
                if (naclp) {
4282
                    while (*naclp)
4283
                        naclp = &(*naclp)->next;
4284

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

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

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

    
4399

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

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

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

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

    
4455
static void handle_child_exit(int sig)
4456
{
4457
    pid_t pid;
4458
    int status;
4459

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

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

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

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

    
4478
    need_to_start_children = 1;
4479
}
4480

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

    
4487
    av_register_all();
4488

    
4489
    config_filename = "/etc/ffserver.conf";
4490

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

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

    
4522
    putenv("http_proxy");               /* Kill the http_proxy */
4523

    
4524
    srandom(gettime_ms() + (getpid() << 16));
4525

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

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

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

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

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

    
4551
    build_file_streams();
4552

    
4553
    build_feed_streams();
4554

    
4555
    compute_bandwidth();
4556

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

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

    
4583
    /* signal init */
4584
    signal(SIGPIPE, SIG_IGN);
4585

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

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

    
4599
    return 0;
4600
}