Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 59006372

History | View | Annotate | Download (152 KB)

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

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

    
46
#include "version.h"
47
#include "ffserver.h"
48
#include "random.h"
49

    
50
#undef exit
51

    
52
/* maximum number of simultaneous HTTP connections */
53
#define HTTP_MAX_CONNECTIONS 2000
54

    
55
enum HTTPState {
56
    HTTPSTATE_WAIT_REQUEST,
57
    HTTPSTATE_SEND_HEADER,
58
    HTTPSTATE_SEND_DATA_HEADER,
59
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
60
    HTTPSTATE_SEND_DATA_TRAILER,
61
    HTTPSTATE_RECEIVE_DATA,
62
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
63
    HTTPSTATE_READY,
64

    
65
    RTSPSTATE_WAIT_REQUEST,
66
    RTSPSTATE_SEND_REPLY,
67
    RTSPSTATE_SEND_PACKET,
68
};
69

    
70
const char *http_state[] = {
71
    "HTTP_WAIT_REQUEST",
72
    "HTTP_SEND_HEADER",
73

    
74
    "SEND_DATA_HEADER",
75
    "SEND_DATA",
76
    "SEND_DATA_TRAILER",
77
    "RECEIVE_DATA",
78
    "WAIT_FEED",
79
    "READY",
80

    
81
    "RTSP_WAIT_REQUEST",
82
    "RTSP_SEND_REPLY",
83
    "RTSP_SEND_PACKET",
84
};
85

    
86
#define IOBUFFER_INIT_SIZE 8192
87

    
88
/* coef for exponential mean for bitrate estimation in statistics */
89
#define AVG_COEF 0.9
90

    
91
/* timeouts are in ms */
92
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
93
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
94

    
95
#define SYNC_TIMEOUT (10 * 1000)
96

    
97
typedef struct {
98
    int64_t count1, count2;
99
    int64_t time1, time2;
100
} DataRateData;
101

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

    
147
    /* RTSP state specific */
148
    uint8_t *pb_buffer; /* XXX: use that in all the code */
149
    ByteIOContext *pb;
150
    int seq; /* RTSP sequence number */
151

    
152
    /* RTP state specific */
153
    enum RTSPProtocol rtp_protocol;
154
    char session_id[32]; /* session id */
155
    AVFormatContext *rtp_ctx[MAX_STREAMS];
156

    
157
    /* RTP/UDP specific */
158
    URLContext *rtp_handles[MAX_STREAMS];
159

    
160
    /* RTP/TCP specific */
161
    struct HTTPContext *rtsp_c;
162
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
163
} HTTPContext;
164

    
165
static AVFrame dummy_frame;
166

    
167
/* each generated stream is described here */
168
enum StreamType {
169
    STREAM_TYPE_LIVE,
170
    STREAM_TYPE_STATUS,
171
    STREAM_TYPE_REDIRECT,
172
};
173

    
174
enum IPAddressAction {
175
    IP_ALLOW = 1,
176
    IP_DENY,
177
};
178

    
179
typedef struct IPAddressACL {
180
    struct IPAddressACL *next;
181
    enum IPAddressAction action;
182
    /* These are in host order */
183
    struct in_addr first;
184
    struct in_addr last;
185
} IPAddressACL;
186

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

    
223
    /* feed specific */
224
    int feed_opened;     /* true if someone is writing to the feed */
225
    int is_feed;         /* true if it is a feed */
226
    int readonly;        /* True if writing is prohibited to the file */
227
    int conns_served;
228
    int64_t bytes_served;
229
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
230
    int64_t feed_write_index;   /* current write position in feed (it wraps round) */
231
    int64_t feed_size;          /* current size of feed */
232
    struct FFStream *next_feed;
233
} FFStream;
234

    
235
typedef struct FeedData {
236
    long long data_count;
237
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
238
} FeedData;
239

    
240
struct sockaddr_in my_http_addr;
241
struct sockaddr_in my_rtsp_addr;
242

    
243
static char logfilename[1024];
244
static HTTPContext *first_http_ctx;
245
static FFStream *first_feed;   /* contains only feeds */
246
static FFStream *first_stream; /* contains all streams, including feeds */
247

    
248
static void new_connection(int server_fd, int is_rtsp);
249
static void close_connection(HTTPContext *c);
250

    
251
/* HTTP handling */
252
static int handle_connection(HTTPContext *c);
253
static int http_parse_request(HTTPContext *c);
254
static int http_send_data(HTTPContext *c);
255
static void compute_stats(HTTPContext *c);
256
static int open_input_stream(HTTPContext *c, const char *info);
257
static int http_start_receive_data(HTTPContext *c);
258
static int http_receive_data(HTTPContext *c);
259

    
260
/* RTSP handling */
261
static int rtsp_parse_request(HTTPContext *c);
262
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
263
static void rtsp_cmd_options(HTTPContext *c, const char *url);
264
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
265
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
266
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
267
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
268

    
269
/* SDP handling */
270
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
271
                                   struct in_addr my_ip);
272

    
273
/* RTP handling */
274
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
275
                                       FFStream *stream, const char *session_id,
276
                                       enum RTSPProtocol rtp_protocol);
277
static int rtp_new_av_stream(HTTPContext *c,
278
                             int stream_index, struct sockaddr_in *dest_addr,
279
                             HTTPContext *rtsp_c);
280

    
281
static const char *my_program_name;
282
static const char *my_program_dir;
283

    
284
static int ffserver_debug;
285
static int ffserver_daemon;
286
static int no_launch;
287
static int need_to_start_children;
288

    
289
static int nb_max_connections;
290
static int nb_connections;
291

    
292
static int max_bandwidth;
293
static int current_bandwidth;
294

    
295
static int64_t cur_time;           // Making this global saves on passing it around everywhere
296

    
297
static AVRandomState random_state;
298

    
299
static FILE *logfile = NULL;
300

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

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

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

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

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

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

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

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

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

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

    
364

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

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

    
374
            feed->pid = fork();
375

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

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

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

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

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

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

    
413
                signal(SIGPIPE, SIG_DFL);
414

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

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

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

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

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

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

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

    
452
    return server_fd;
453
}
454

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

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

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

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

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

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

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

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

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

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

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

    
527
    start_children(first_feed);
528

    
529
    first_http_ctx = NULL;
530
    nb_connections = 0;
531

    
532
    start_multicast();
533

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

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

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

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

    
602
        cur_time = av_gettime() / 1000;
603

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

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

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

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

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

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

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

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

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

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

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

    
682
    start_wait_request(c, is_rtsp);
683

    
684
    return;
685

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

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

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

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

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

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

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

    
750
    ctx = &c->fmt_ctx;
751

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

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

    
765
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
766
        current_bandwidth -= c->stream->bandwidth;
767

    
768
    /* signal that there is no feed if we are the feeder socket */
769
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
770
        c->stream->feed_opened = 0;
771
        close(c->feed_fd);
772
    }
773

    
774
    av_freep(&c->pb_buffer);
775
    av_freep(&c->packet_buffer);
776
    av_free(c->buffer);
777
    av_free(c);
778
    nb_connections--;
779
}
780

    
781
static int handle_connection(HTTPContext *c)
782
{
783
    int len, ret;
784

    
785
    switch(c->state) {
786
    case HTTPSTATE_WAIT_REQUEST:
787
    case RTSPSTATE_WAIT_REQUEST:
788
        /* timeout ? */
789
        if ((c->timeout - cur_time) < 0)
790
            return -1;
791
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
792
            return -1;
793

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

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

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

    
859
    case HTTPSTATE_SEND_DATA:
860
    case HTTPSTATE_SEND_DATA_HEADER:
861
    case HTTPSTATE_SEND_DATA_TRAILER:
862
        /* for packetized output, we consider we can always write (the
863
           input streams sets the speed). It may be better to verify
864
           that we do not rely too much on the kernel queues */
865
        if (!c->is_packetized) {
866
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
867
                return -1;
868

    
869
            /* no need to read if no events */
870
            if (!(c->poll_entry->revents & POLLOUT))
871
                return 0;
872
        }
873
        if (http_send_data(c) < 0)
874
            return -1;
875
        /* close connection if trailer sent */
876
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
877
            return -1;
878
        break;
879
    case HTTPSTATE_RECEIVE_DATA:
880
        /* no need to read if no events */
881
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
882
            return -1;
883
        if (!(c->poll_entry->revents & POLLIN))
884
            return 0;
885
        if (http_receive_data(c) < 0)
886
            return -1;
887
        break;
888
    case HTTPSTATE_WAIT_FEED:
889
        /* no need to read if no events */
890
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
891
            return -1;
892

    
893
        /* nothing to do, we'll be waken up by incoming feed packets */
894
        break;
895

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

    
955
static int extract_rates(char *rates, int ratelen, const char *request)
956
{
957
    const char *p;
958

    
959
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
960
        if (strncasecmp(p, "Pragma:", 7) == 0) {
961
            const char *q = p + 7;
962

    
963
            while (*q && *q != '\n' && isspace(*q))
964
                q++;
965

    
966
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
967
                int stream_no;
968
                int rate_no;
969

    
970
                q += 20;
971

    
972
                memset(rates, 0xff, ratelen);
973

    
974
                while (1) {
975
                    while (*q && *q != '\n' && *q != ':')
976
                        q++;
977

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

    
986
                    while (*q && *q != '\n' && !isspace(*q))
987
                        q++;
988
                }
989

    
990
                return 1;
991
            }
992
        }
993
        p = strchr(p, '\n');
994
        if (!p)
995
            break;
996

    
997
        p++;
998
    }
999

    
1000
    return 0;
1001
}
1002

    
1003
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1004
{
1005
    int i;
1006
    int best_bitrate = 100000000;
1007
    int best = -1;
1008

    
1009
    for (i = 0; i < feed->nb_streams; i++) {
1010
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1011

    
1012
        if (feed_codec->codec_id != codec->codec_id ||
1013
            feed_codec->sample_rate != codec->sample_rate ||
1014
            feed_codec->width != codec->width ||
1015
            feed_codec->height != codec->height) {
1016
            continue;
1017
        }
1018

    
1019
        /* Potential stream */
1020

    
1021
        /* We want the fastest stream less than bit_rate, or the slowest
1022
         * faster than bit_rate
1023
         */
1024

    
1025
        if (feed_codec->bit_rate <= bit_rate) {
1026
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1027
                best_bitrate = feed_codec->bit_rate;
1028
                best = i;
1029
            }
1030
        } else {
1031
            if (feed_codec->bit_rate < best_bitrate) {
1032
                best_bitrate = feed_codec->bit_rate;
1033
                best = i;
1034
            }
1035
        }
1036
    }
1037

    
1038
    return best;
1039
}
1040

    
1041
static int modify_current_stream(HTTPContext *c, char *rates)
1042
{
1043
    int i;
1044
    FFStream *req = c->stream;
1045
    int action_required = 0;
1046

    
1047
    /* Not much we can do for a feed */
1048
    if (!req->feed)
1049
        return 0;
1050

    
1051
    for (i = 0; i < req->nb_streams; i++) {
1052
        AVCodecContext *codec = req->streams[i]->codec;
1053

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

    
1072
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1073
            action_required = 1;
1074
    }
1075

    
1076
    return action_required;
1077
}
1078

    
1079

    
1080
static void do_switch_stream(HTTPContext *c, int i)
1081
{
1082
    if (c->switch_feed_streams[i] >= 0) {
1083
#ifdef PHILIP
1084
        c->feed_streams[i] = c->switch_feed_streams[i];
1085
#endif
1086

    
1087
        /* Now update the stream */
1088
    }
1089
    c->switch_feed_streams[i] = -1;
1090
}
1091

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

    
1103
static void get_word(char *buf, int buf_size, const char **pp)
1104
{
1105
    const char *p;
1106
    char *q;
1107

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

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

    
1128
    for (acl = stream->acl; acl; acl = acl->next) {
1129
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1130
            return (acl->action == IP_ALLOW) ? 1 : 0;
1131
        }
1132
        last_action = acl->action;
1133
    }
1134

    
1135
    /* Nothing matched, so return not the last action */
1136
    return (last_action == IP_DENY) ? 1 : 0;
1137
}
1138

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

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

    
1165
enum RedirType {
1166
    REDIR_NONE,
1167
    REDIR_ASX,
1168
    REDIR_RAM,
1169
    REDIR_ASF,
1170
    REDIR_RTSP,
1171
    REDIR_SDP,
1172
};
1173

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

    
1190
    p = c->buffer;
1191
    get_word(cmd, sizeof(cmd), (const char **)&p);
1192
    pstrcpy(c->method, sizeof(c->method), cmd);
1193

    
1194
    if (!strcmp(cmd, "GET"))
1195
        c->post = 0;
1196
    else if (!strcmp(cmd, "POST"))
1197
        c->post = 1;
1198
    else
1199
        return -1;
1200

    
1201
    get_word(url, sizeof(url), (const char **)&p);
1202
    pstrcpy(c->url, sizeof(c->url), url);
1203

    
1204
    get_word(protocol, sizeof(protocol), (const char **)&p);
1205
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1206
        return -1;
1207

    
1208
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1209

    
1210
    if (ffserver_debug)
1211
        http_log("New connection: %s %s\n", cmd, url);
1212

    
1213
    /* find the filename and the optional info string in the request */
1214
    p = strchr(url, '?');
1215
    if (p) {
1216
        pstrcpy(info, sizeof(info), p);
1217
        *p = '\0';
1218
    } else {
1219
        info[0] = '\0';
1220
    }
1221

    
1222
    pstrcpy(filename, sizeof(filename)-1, url + ((*url == '/') ? 1 : 0));
1223

    
1224
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1225
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1226
            useragent = p + 11;
1227
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1228
                useragent++;
1229
            break;
1230
        }
1231
        p = strchr(p, '\n');
1232
        if (!p)
1233
            break;
1234

    
1235
        p++;
1236
    }
1237

    
1238
    redir_type = REDIR_NONE;
1239
    if (match_ext(filename, "asx")) {
1240
        redir_type = REDIR_ASX;
1241
        filename[strlen(filename)-1] = 'f';
1242
    } else if (match_ext(filename, "asf") &&
1243
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1244
        /* if this isn't WMP or lookalike, return the redirector file */
1245
        redir_type = REDIR_ASF;
1246
    } else if (match_ext(filename, "rpm,ram")) {
1247
        redir_type = REDIR_RAM;
1248
        strcpy(filename + strlen(filename)-2, "m");
1249
    } else if (match_ext(filename, "rtsp")) {
1250
        redir_type = REDIR_RTSP;
1251
        compute_real_filename(filename, sizeof(filename) - 1);
1252
    } else if (match_ext(filename, "sdp")) {
1253
        redir_type = REDIR_SDP;
1254
        compute_real_filename(filename, sizeof(filename) - 1);
1255
    }
1256

    
1257
    // "redirect" / request to index.html
1258
    if (!strlen(filename))
1259
        pstrcpy(filename, sizeof(filename) - 1, "index.html");
1260

    
1261
    stream = first_stream;
1262
    while (stream != NULL) {
1263
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1264
            break;
1265
        stream = stream->next;
1266
    }
1267
    if (stream == NULL) {
1268
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1269
        goto send_error;
1270
    }
1271

    
1272
    c->stream = stream;
1273
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1274
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1275

    
1276
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1277
        c->http_error = 301;
1278
        q = c->buffer;
1279
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1280
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1281
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1282
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1283
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1284
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1285
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1286

    
1287
        /* prepare output buffer */
1288
        c->buffer_ptr = c->buffer;
1289
        c->buffer_end = q;
1290
        c->state = HTTPSTATE_SEND_HEADER;
1291
        return 0;
1292
    }
1293

    
1294
    /* If this is WMP, get the rate information */
1295
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1296
        if (modify_current_stream(c, ratebuf)) {
1297
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1298
                if (c->switch_feed_streams[i] >= 0)
1299
                    do_switch_stream(c, i);
1300
            }
1301
        }
1302
    }
1303

    
1304
    /* If already streaming this feed, dont let start an another feeder */
1305
    if (stream->feed_opened) {
1306
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1307
        goto send_error;
1308
    }
1309

    
1310
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1311
        current_bandwidth += stream->bandwidth;
1312
    }
1313

    
1314
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1315
        c->http_error = 200;
1316
        q = c->buffer;
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1318
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1321
        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");
1322
        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",
1323
            current_bandwidth, max_bandwidth);
1324
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1325

    
1326
        /* prepare output buffer */
1327
        c->buffer_ptr = c->buffer;
1328
        c->buffer_end = q;
1329
        c->state = HTTPSTATE_SEND_HEADER;
1330
        return 0;
1331
    }
1332

    
1333
    if (redir_type != REDIR_NONE) {
1334
        char *hostinfo = 0;
1335

    
1336
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1337
            if (strncasecmp(p, "Host:", 5) == 0) {
1338
                hostinfo = p + 5;
1339
                break;
1340
            }
1341
            p = strchr(p, '\n');
1342
            if (!p)
1343
                break;
1344

    
1345
            p++;
1346
        }
1347

    
1348
        if (hostinfo) {
1349
            char *eoh;
1350
            char hostbuf[260];
1351

    
1352
            while (isspace(*hostinfo))
1353
                hostinfo++;
1354

    
1355
            eoh = strchr(hostinfo, '\n');
1356
            if (eoh) {
1357
                if (eoh[-1] == '\r')
1358
                    eoh--;
1359

    
1360
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1361
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1362
                    hostbuf[eoh - hostinfo] = 0;
1363

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

    
1416
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1417
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1418
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1419

    
1420
                            len = sizeof(my_addr);
1421
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1422

    
1423
                            /* XXX: should use a dynamic buffer */
1424
                            sdp_data_size = prepare_sdp_description(stream,
1425
                                                                    &sdp_data,
1426
                                                                    my_addr.sin_addr);
1427
                            if (sdp_data_size > 0) {
1428
                                memcpy(q, sdp_data, sdp_data_size);
1429
                                q += sdp_data_size;
1430
                                *q = '\0';
1431
                                av_free(sdp_data);
1432
                            }
1433
                        }
1434
                        break;
1435
                    default:
1436
                        av_abort();
1437
                        break;
1438
                    }
1439

    
1440
                    /* prepare output buffer */
1441
                    c->buffer_ptr = c->buffer;
1442
                    c->buffer_end = q;
1443
                    c->state = HTTPSTATE_SEND_HEADER;
1444
                    return 0;
1445
                }
1446
            }
1447
        }
1448

    
1449
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1450
        goto send_error;
1451
    }
1452

    
1453
    stream->conns_served++;
1454

    
1455
    /* XXX: add there authenticate and IP match */
1456

    
1457
    if (c->post) {
1458
        /* if post, it means a feed is being sent */
1459
        if (!stream->is_feed) {
1460
            /* However it might be a status report from WMP! Lets log the data
1461
             * as it might come in handy one day
1462
             */
1463
            char *logline = 0;
1464
            int client_id = 0;
1465

    
1466
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1467
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1468
                    logline = p;
1469
                    break;
1470
                }
1471
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1472
                    client_id = strtol(p + 18, 0, 10);
1473
                }
1474
                p = strchr(p, '\n');
1475
                if (!p)
1476
                    break;
1477

    
1478
                p++;
1479
            }
1480

    
1481
            if (logline) {
1482
                char *eol = strchr(logline, '\n');
1483

    
1484
                logline += 17;
1485

    
1486
                if (eol) {
1487
                    if (eol[-1] == '\r')
1488
                        eol--;
1489
                    http_log("%.*s\n", (int) (eol - logline), logline);
1490
                    c->suppress_log = 1;
1491
                }
1492
            }
1493

    
1494
#ifdef DEBUG_WMP
1495
            http_log("\nGot request:\n%s\n", c->buffer);
1496
#endif
1497

    
1498
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1499
                HTTPContext *wmpc;
1500

    
1501
                /* Now we have to find the client_id */
1502
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1503
                    if (wmpc->wmp_client_id == client_id)
1504
                        break;
1505
                }
1506

    
1507
                if (wmpc) {
1508
                    if (modify_current_stream(wmpc, ratebuf)) {
1509
                        wmpc->switch_pending = 1;
1510
                    }
1511
                }
1512
            }
1513

    
1514
            snprintf(msg, sizeof(msg), "POST command not handled");
1515
            c->stream = 0;
1516
            goto send_error;
1517
        }
1518
        if (http_start_receive_data(c) < 0) {
1519
            snprintf(msg, sizeof(msg), "could not open feed");
1520
            goto send_error;
1521
        }
1522
        c->http_error = 0;
1523
        c->state = HTTPSTATE_RECEIVE_DATA;
1524
        return 0;
1525
    }
1526

    
1527
#ifdef DEBUG_WMP
1528
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1529
        http_log("\nGot request:\n%s\n", c->buffer);
1530
    }
1531
#endif
1532

    
1533
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1534
        goto send_stats;
1535

    
1536
    /* open input stream */
1537
    if (open_input_stream(c, info) < 0) {
1538
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1539
        goto send_error;
1540
    }
1541

    
1542
    /* prepare http header */
1543
    q = c->buffer;
1544
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1545
    mime_type = c->stream->fmt->mime_type;
1546
    if (!mime_type)
1547
        mime_type = "application/x-octet_stream";
1548
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1549

    
1550
    /* for asf, we need extra headers */
1551
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1552
        /* Need to allocate a client id */
1553

    
1554
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1555

    
1556
        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);
1557
    }
1558
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1559
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1560

    
1561
    /* prepare output buffer */
1562
    c->http_error = 0;
1563
    c->buffer_ptr = c->buffer;
1564
    c->buffer_end = q;
1565
    c->state = HTTPSTATE_SEND_HEADER;
1566
    return 0;
1567
 send_error:
1568
    c->http_error = 404;
1569
    q = c->buffer;
1570
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1571
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1572
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1573
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1574
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1575
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1576
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1577

    
1578
    /* prepare output buffer */
1579
    c->buffer_ptr = c->buffer;
1580
    c->buffer_end = q;
1581
    c->state = HTTPSTATE_SEND_HEADER;
1582
    return 0;
1583
 send_stats:
1584
    compute_stats(c);
1585
    c->http_error = 200; /* horrible : we use this value to avoid
1586
                            going to the send data state */
1587
    c->state = HTTPSTATE_SEND_HEADER;
1588
    return 0;
1589
}
1590

    
1591
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1592
{
1593
    static const char *suffix = " kMGTP";
1594
    const char *s;
1595

    
1596
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1597
    }
1598

    
1599
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1600
}
1601

    
1602
static void compute_stats(HTTPContext *c)
1603
{
1604
    HTTPContext *c1;
1605
    FFStream *stream;
1606
    char *p;
1607
    time_t ti;
1608
    int i, len;
1609
    ByteIOContext pb1, *pb = &pb1;
1610

    
1611
    if (url_open_dyn_buf(pb) < 0) {
1612
        /* XXX: return an error ? */
1613
        c->buffer_ptr = c->buffer;
1614
        c->buffer_end = c->buffer;
1615
        return;
1616
    }
1617

    
1618
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1619
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1620
    url_fprintf(pb, "Pragma: no-cache\r\n");
1621
    url_fprintf(pb, "\r\n");
1622

    
1623
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1624
    if (c->stream->feed_filename) {
1625
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1626
    }
1627
    url_fprintf(pb, "</HEAD>\n<BODY>");
1628
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1629
    /* format status */
1630
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1631
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1632
    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");
1633
    stream = first_stream;
1634
    while (stream != NULL) {
1635
        char sfilename[1024];
1636
        char *eosf;
1637

    
1638
        if (stream->feed != stream) {
1639
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1640
            eosf = sfilename + strlen(sfilename);
1641
            if (eosf - sfilename >= 4) {
1642
                if (strcmp(eosf - 4, ".asf") == 0) {
1643
                    strcpy(eosf - 4, ".asx");
1644
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1645
                    strcpy(eosf - 3, ".ram");
1646
                } else if (stream->fmt == &rtp_muxer) {
1647
                    /* generate a sample RTSP director if
1648
                       unicast. Generate an SDP redirector if
1649
                       multicast */
1650
                    eosf = strrchr(sfilename, '.');
1651
                    if (!eosf)
1652
                        eosf = sfilename + strlen(sfilename);
1653
                    if (stream->is_multicast)
1654
                        strcpy(eosf, ".sdp");
1655
                    else
1656
                        strcpy(eosf, ".rtsp");
1657
                }
1658
            }
1659

    
1660
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1661
                         sfilename, stream->filename);
1662
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1663
                        stream->conns_served);
1664
            fmt_bytecount(pb, stream->bytes_served);
1665
            switch(stream->stream_type) {
1666
            case STREAM_TYPE_LIVE:
1667
                {
1668
                    int audio_bit_rate = 0;
1669
                    int video_bit_rate = 0;
1670
                    const char *audio_codec_name = "";
1671
                    const char *video_codec_name = "";
1672
                    const char *audio_codec_name_extra = "";
1673
                    const char *video_codec_name_extra = "";
1674

    
1675
                    for(i=0;i<stream->nb_streams;i++) {
1676
                        AVStream *st = stream->streams[i];
1677
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1678
                        switch(st->codec->codec_type) {
1679
                        case CODEC_TYPE_AUDIO:
1680
                            audio_bit_rate += st->codec->bit_rate;
1681
                            if (codec) {
1682
                                if (*audio_codec_name)
1683
                                    audio_codec_name_extra = "...";
1684
                                audio_codec_name = codec->name;
1685
                            }
1686
                            break;
1687
                        case CODEC_TYPE_VIDEO:
1688
                            video_bit_rate += st->codec->bit_rate;
1689
                            if (codec) {
1690
                                if (*video_codec_name)
1691
                                    video_codec_name_extra = "...";
1692
                                video_codec_name = codec->name;
1693
                            }
1694
                            break;
1695
                        case CODEC_TYPE_DATA:
1696
                            video_bit_rate += st->codec->bit_rate;
1697
                            break;
1698
                        default:
1699
                            av_abort();
1700
                        }
1701
                    }
1702
                    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",
1703
                                 stream->fmt->name,
1704
                                 stream->bandwidth,
1705
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1706
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1707
                    if (stream->feed) {
1708
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1709
                    } else {
1710
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1711
                    }
1712
                    url_fprintf(pb, "\n");
1713
                }
1714
                break;
1715
            default:
1716
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1717
                break;
1718
            }
1719
        }
1720
        stream = stream->next;
1721
    }
1722
    url_fprintf(pb, "</TABLE>\n");
1723

    
1724
    stream = first_stream;
1725
    while (stream != NULL) {
1726
        if (stream->feed == stream) {
1727
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1728
            if (stream->pid) {
1729
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1730

    
1731
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1732
                {
1733
                    FILE *pid_stat;
1734
                    char ps_cmd[64];
1735

    
1736
                    /* This is somewhat linux specific I guess */
1737
                    snprintf(ps_cmd, sizeof(ps_cmd),
1738
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1739
                             stream->pid);
1740

    
1741
                    pid_stat = popen(ps_cmd, "r");
1742
                    if (pid_stat) {
1743
                        char cpuperc[10];
1744
                        char cpuused[64];
1745

    
1746
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1747
                                   cpuused) == 2) {
1748
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1749
                                         cpuperc, cpuused);
1750
                        }
1751
                        fclose(pid_stat);
1752
                    }
1753
                }
1754
#endif
1755

    
1756
                url_fprintf(pb, "<p>");
1757
            }
1758
            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");
1759

    
1760
            for (i = 0; i < stream->nb_streams; i++) {
1761
                AVStream *st = stream->streams[i];
1762
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1763
                const char *type = "unknown";
1764
                char parameters[64];
1765

    
1766
                parameters[0] = 0;
1767

    
1768
                switch(st->codec->codec_type) {
1769
                case CODEC_TYPE_AUDIO:
1770
                    type = "audio";
1771
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1772
                    break;
1773
                case CODEC_TYPE_VIDEO:
1774
                    type = "video";
1775
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1776
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1777
                    break;
1778
                default:
1779
                    av_abort();
1780
                }
1781
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1782
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1783
            }
1784
            url_fprintf(pb, "</table>\n");
1785

    
1786
        }
1787
        stream = stream->next;
1788
    }
1789

    
1790
#if 0
1791
    {
1792
        float avg;
1793
        AVCodecContext *enc;
1794
        char buf[1024];
1795

1796
        /* feed status */
1797
        stream = first_feed;
1798
        while (stream != NULL) {
1799
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1800
            url_fprintf(pb, "<TABLE>\n");
1801
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1802
            for(i=0;i<stream->nb_streams;i++) {
1803
                AVStream *st = stream->streams[i];
1804
                FeedData *fdata = st->priv_data;
1805
                enc = st->codec;
1806

1807
                avcodec_string(buf, sizeof(buf), enc);
1808
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1809
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1810
                    avg /= enc->frame_size;
1811
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1812
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1813
            }
1814
            url_fprintf(pb, "</TABLE>\n");
1815
            stream = stream->next_feed;
1816
        }
1817
    }
1818
#endif
1819

    
1820
    /* connection status */
1821
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1822

    
1823
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1824
                 nb_connections, nb_max_connections);
1825

    
1826
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1827
                 current_bandwidth, max_bandwidth);
1828

    
1829
    url_fprintf(pb, "<TABLE>\n");
1830
    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");
1831
    c1 = first_http_ctx;
1832
    i = 0;
1833
    while (c1 != NULL) {
1834
        int bitrate;
1835
        int j;
1836

    
1837
        bitrate = 0;
1838
        if (c1->stream) {
1839
            for (j = 0; j < c1->stream->nb_streams; j++) {
1840
                if (!c1->stream->feed) {
1841
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1842
                } else {
1843
                    if (c1->feed_streams[j] >= 0) {
1844
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1845
                    }
1846
                }
1847
            }
1848
        }
1849

    
1850
        i++;
1851
        p = inet_ntoa(c1->from_addr.sin_addr);
1852
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1853
                    i,
1854
                    c1->stream ? c1->stream->filename : "",
1855
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1856
                    p,
1857
                    c1->protocol,
1858
                    http_state[c1->state]);
1859
        fmt_bytecount(pb, bitrate);
1860
        url_fprintf(pb, "<td align=right>");
1861
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1862
        url_fprintf(pb, "<td align=right>");
1863
        fmt_bytecount(pb, c1->data_count);
1864
        url_fprintf(pb, "\n");
1865
        c1 = c1->next;
1866
    }
1867
    url_fprintf(pb, "</TABLE>\n");
1868

    
1869
    /* date */
1870
    ti = time(NULL);
1871
    p = ctime(&ti);
1872
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1873
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1874

    
1875
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1876
    c->buffer_ptr = c->pb_buffer;
1877
    c->buffer_end = c->pb_buffer + len;
1878
}
1879

    
1880
/* check if the parser needs to be opened for stream i */
1881
static void open_parser(AVFormatContext *s, int i)
1882
{
1883
    AVStream *st = s->streams[i];
1884
    AVCodec *codec;
1885

    
1886
    if (!st->codec->codec) {
1887
        codec = avcodec_find_decoder(st->codec->codec_id);
1888
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1889
            st->codec->parse_only = 1;
1890
            if (avcodec_open(st->codec, codec) < 0) {
1891
                st->codec->parse_only = 0;
1892
            }
1893
        }
1894
    }
1895
}
1896

    
1897
static int open_input_stream(HTTPContext *c, const char *info)
1898
{
1899
    char buf[128];
1900
    char input_filename[1024];
1901
    AVFormatContext *s;
1902
    int buf_size, i;
1903
    int64_t stream_pos;
1904

    
1905
    /* find file name */
1906
    if (c->stream->feed) {
1907
        strcpy(input_filename, c->stream->feed->feed_filename);
1908
        buf_size = FFM_PACKET_SIZE;
1909
        /* compute position (absolute time) */
1910
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1911
            stream_pos = parse_date(buf, 0);
1912
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1913
            int prebuffer = strtol(buf, 0, 10);
1914
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1915
        } else {
1916
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1917
        }
1918
    } else {
1919
        strcpy(input_filename, c->stream->feed_filename);
1920
        buf_size = 0;
1921
        /* compute position (relative time) */
1922
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1923
            stream_pos = parse_date(buf, 1);
1924
        } else {
1925
            stream_pos = 0;
1926
        }
1927
    }
1928
    if (input_filename[0] == '\0')
1929
        return -1;
1930

    
1931
#if 0
1932
    { time_t when = stream_pos / 1000000;
1933
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1934
    }
1935
#endif
1936

    
1937
    /* open stream */
1938
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1939
                           buf_size, c->stream->ap_in) < 0) {
1940
        http_log("%s not found", input_filename);
1941
        return -1;
1942
    }
1943
    c->fmt_in = s;
1944

    
1945
    /* open each parser */
1946
    for(i=0;i<s->nb_streams;i++)
1947
        open_parser(s, i);
1948

    
1949
    /* choose stream as clock source (we favorize video stream if
1950
       present) for packet sending */
1951
    c->pts_stream_index = 0;
1952
    for(i=0;i<c->stream->nb_streams;i++) {
1953
        if (c->pts_stream_index == 0 &&
1954
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1955
            c->pts_stream_index = i;
1956
        }
1957
    }
1958

    
1959
#if 1
1960
    if (c->fmt_in->iformat->read_seek) {
1961
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1962
    }
1963
#endif
1964
    /* set the start time (needed for maxtime and RTP packet timing) */
1965
    c->start_time = cur_time;
1966
    c->first_pts = AV_NOPTS_VALUE;
1967
    return 0;
1968
}
1969

    
1970
/* return the server clock (in us) */
1971
static int64_t get_server_clock(HTTPContext *c)
1972
{
1973
    /* compute current pts value from system time */
1974
    return (cur_time - c->start_time) * 1000;
1975
}
1976

    
1977
/* return the estimated time at which the current packet must be sent
1978
   (in us) */
1979
static int64_t get_packet_send_clock(HTTPContext *c)
1980
{
1981
    int bytes_left, bytes_sent, frame_bytes;
1982

    
1983
    frame_bytes = c->cur_frame_bytes;
1984
    if (frame_bytes <= 0) {
1985
        return c->cur_pts;
1986
    } else {
1987
        bytes_left = c->buffer_end - c->buffer_ptr;
1988
        bytes_sent = frame_bytes - bytes_left;
1989
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1990
    }
1991
}
1992

    
1993

    
1994
static int http_prepare_data(HTTPContext *c)
1995
{
1996
    int i, len, ret;
1997
    AVFormatContext *ctx;
1998

    
1999
    av_freep(&c->pb_buffer);
2000
    switch(c->state) {
2001
    case HTTPSTATE_SEND_DATA_HEADER:
2002
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2003
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
2004
                c->stream->author);
2005
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
2006
                c->stream->comment);
2007
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
2008
                c->stream->copyright);
2009
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
2010
                c->stream->title);
2011

    
2012
        /* open output stream by using specified codecs */
2013
        c->fmt_ctx.oformat = c->stream->fmt;
2014
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2015
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2016
            AVStream *st;
2017
            AVStream *src;
2018
            st = av_mallocz(sizeof(AVStream));
2019
            st->codec= avcodec_alloc_context();
2020
            c->fmt_ctx.streams[i] = st;
2021
            /* if file or feed, then just take streams from FFStream struct */
2022
            if (!c->stream->feed ||
2023
                c->stream->feed == c->stream)
2024
                src = c->stream->streams[i];
2025
            else
2026
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2027

    
2028
            *st = *src;
2029
            st->priv_data = 0;
2030
            st->codec->frame_number = 0; /* XXX: should be done in
2031
                                           AVStream, not in codec */
2032
            /* I'm pretty sure that this is not correct...
2033
             * However, without it, we crash
2034
             */
2035
            st->codec->coded_frame = &dummy_frame;
2036
        }
2037
        c->got_key_frame = 0;
2038

    
2039
        /* prepare header and save header data in a stream */
2040
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2041
            /* XXX: potential leak */
2042
            return -1;
2043
        }
2044
        c->fmt_ctx.pb.is_streamed = 1;
2045

    
2046
        av_set_parameters(&c->fmt_ctx, NULL);
2047
        if (av_write_header(&c->fmt_ctx) < 0)
2048
            return -1;
2049

    
2050
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2051
        c->buffer_ptr = c->pb_buffer;
2052
        c->buffer_end = c->pb_buffer + len;
2053

    
2054
        c->state = HTTPSTATE_SEND_DATA;
2055
        c->last_packet_sent = 0;
2056
        break;
2057
    case HTTPSTATE_SEND_DATA:
2058
        /* find a new packet */
2059
        {
2060
            AVPacket pkt;
2061

    
2062
            /* read a packet from the input stream */
2063
            if (c->stream->feed) {
2064
                ffm_set_write_index(c->fmt_in,
2065
                                    c->stream->feed->feed_write_index,
2066
                                    c->stream->feed->feed_size);
2067
            }
2068

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

    
2138
                    send_it:
2139
                        /* specific handling for RTP: we use several
2140
                           output stream (one for each RTP
2141
                           connection). XXX: need more abstract handling */
2142
                        if (c->is_packetized) {
2143
                            AVStream *st;
2144
                            /* compute send time and duration */
2145
                            st = c->fmt_in->streams[pkt.stream_index];
2146
                            c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2147
                            if (st->start_time != AV_NOPTS_VALUE)
2148
                                c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2149
                            c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2150
#if 0
2151
                            printf("index=%d pts=%0.3f duration=%0.6f\n",
2152
                                   pkt.stream_index,
2153
                                   (double)c->cur_pts /
2154
                                   AV_TIME_BASE,
2155
                                   (double)c->cur_frame_duration /
2156
                                   AV_TIME_BASE);
2157
#endif
2158
                            /* find RTP context */
2159
                            c->packet_stream_index = pkt.stream_index;
2160
                            ctx = c->rtp_ctx[c->packet_stream_index];
2161
                            if(!ctx) {
2162
                              av_free_packet(&pkt);
2163
                              break;
2164
                            }
2165
                            codec = ctx->streams[0]->codec;
2166
                            /* only one stream per RTP connection */
2167
                            pkt.stream_index = 0;
2168
                        } else {
2169
                            ctx = &c->fmt_ctx;
2170
                            /* Fudge here */
2171
                            codec = ctx->streams[pkt.stream_index]->codec;
2172
                        }
2173

    
2174
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2175
                        if (c->is_packetized) {
2176
                            int max_packet_size;
2177
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2178
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2179
                            else
2180
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2181
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2182
                        } else {
2183
                            ret = url_open_dyn_buf(&ctx->pb);
2184
                        }
2185
                        if (ret < 0) {
2186
                            /* XXX: potential leak */
2187
                            return -1;
2188
                        }
2189
                        if (pkt.dts != AV_NOPTS_VALUE)
2190
                            pkt.dts = av_rescale_q(pkt.dts,
2191
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2192
                                ctx->streams[pkt.stream_index]->time_base);
2193
                        if (pkt.pts != AV_NOPTS_VALUE)
2194
                            pkt.pts = av_rescale_q(pkt.pts,
2195
                                c->fmt_in->streams[pkt.stream_index]->time_base,
2196
                                ctx->streams[pkt.stream_index]->time_base);
2197
                        if (av_write_frame(ctx, &pkt)) {
2198
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2199
                        }
2200

    
2201
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2202
                        c->cur_frame_bytes = len;
2203
                        c->buffer_ptr = c->pb_buffer;
2204
                        c->buffer_end = c->pb_buffer + len;
2205

    
2206
                        codec->frame_number++;
2207
                        if (len == 0)
2208
                            goto redo;
2209
                    }
2210
                    av_free_packet(&pkt);
2211
                }
2212
            }
2213
        }
2214
        break;
2215
    default:
2216
    case HTTPSTATE_SEND_DATA_TRAILER:
2217
        /* last packet test ? */
2218
        if (c->last_packet_sent || c->is_packetized)
2219
            return -1;
2220
        ctx = &c->fmt_ctx;
2221
        /* prepare header */
2222
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2223
            /* XXX: potential leak */
2224
            return -1;
2225
        }
2226
        av_write_trailer(ctx);
2227
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2228
        c->buffer_ptr = c->pb_buffer;
2229
        c->buffer_end = c->pb_buffer + len;
2230

    
2231
        c->last_packet_sent = 1;
2232
        break;
2233
    }
2234
    return 0;
2235
}
2236

    
2237
/* in bit/s */
2238
#define SHORT_TERM_BANDWIDTH 8000000
2239

    
2240
/* should convert the format at the same time */
2241
/* send data starting at c->buffer_ptr to the output connection
2242
   (either UDP or TCP connection) */
2243
static int http_send_data(HTTPContext *c)
2244
{
2245
    int len, ret;
2246

    
2247
    for(;;) {
2248
        if (c->buffer_ptr >= c->buffer_end) {
2249
            ret = http_prepare_data(c);
2250
            if (ret < 0)
2251
                return -1;
2252
            else if (ret != 0) {
2253
                /* state change requested */
2254
                break;
2255
            }
2256
        } else {
2257
            if (c->is_packetized) {
2258
                /* RTP data output */
2259
                len = c->buffer_end - c->buffer_ptr;
2260
                if (len < 4) {
2261
                    /* fail safe - should never happen */
2262
                fail1:
2263
                    c->buffer_ptr = c->buffer_end;
2264
                    return 0;
2265
                }
2266
                len = (c->buffer_ptr[0] << 24) |
2267
                    (c->buffer_ptr[1] << 16) |
2268
                    (c->buffer_ptr[2] << 8) |
2269
                    (c->buffer_ptr[3]);
2270
                if (len > (c->buffer_end - c->buffer_ptr))
2271
                    goto fail1;
2272
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2273
                    /* nothing to send yet: we can wait */
2274
                    return 0;
2275
                }
2276

    
2277
                c->data_count += len;
2278
                update_datarate(&c->datarate, c->data_count);
2279
                if (c->stream)
2280
                    c->stream->bytes_served += len;
2281

    
2282
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2283
                    /* RTP packets are sent inside the RTSP TCP connection */
2284
                    ByteIOContext pb1, *pb = &pb1;
2285
                    int interleaved_index, size;
2286
                    uint8_t header[4];
2287
                    HTTPContext *rtsp_c;
2288

    
2289
                    rtsp_c = c->rtsp_c;
2290
                    /* if no RTSP connection left, error */
2291
                    if (!rtsp_c)
2292
                        return -1;
2293
                    /* if already sending something, then wait. */
2294
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2295
                        break;
2296
                    }
2297
                    if (url_open_dyn_buf(pb) < 0)
2298
                        goto fail1;
2299
                    interleaved_index = c->packet_stream_index * 2;
2300
                    /* RTCP packets are sent at odd indexes */
2301
                    if (c->buffer_ptr[1] == 200)
2302
                        interleaved_index++;
2303
                    /* write RTSP TCP header */
2304
                    header[0] = '$';
2305
                    header[1] = interleaved_index;
2306
                    header[2] = len >> 8;
2307
                    header[3] = len;
2308
                    put_buffer(pb, header, 4);
2309
                    /* write RTP packet data */
2310
                    c->buffer_ptr += 4;
2311
                    put_buffer(pb, c->buffer_ptr, len);
2312
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2313
                    /* prepare asynchronous TCP sending */
2314
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2315
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2316
                    c->buffer_ptr += len;
2317

    
2318
                    /* send everything we can NOW */
2319
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2320
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2321
                    if (len > 0) {
2322
                        rtsp_c->packet_buffer_ptr += len;
2323
                    }
2324
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2325
                        /* if we could not send all the data, we will
2326
                           send it later, so a new state is needed to
2327
                           "lock" the RTSP TCP connection */
2328
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2329
                        break;
2330
                    } else {
2331
                        /* all data has been sent */
2332
                        av_freep(&c->packet_buffer);
2333
                    }
2334
                } else {
2335
                    /* send RTP packet directly in UDP */
2336
                    c->buffer_ptr += 4;
2337
                    url_write(c->rtp_handles[c->packet_stream_index],
2338
                              c->buffer_ptr, len);
2339
                    c->buffer_ptr += len;
2340
                    /* here we continue as we can send several packets per 10 ms slot */
2341
                }
2342
            } else {
2343
                /* TCP data output */
2344
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2345
                if (len < 0) {
2346
                    if (errno != EAGAIN && errno != EINTR) {
2347
                        /* error : close connection */
2348
                        return -1;
2349
                    } else {
2350
                        return 0;
2351
                    }
2352
                } else {
2353
                    c->buffer_ptr += len;
2354
                }
2355
                c->data_count += len;
2356
                update_datarate(&c->datarate, c->data_count);
2357
                if (c->stream)
2358
                    c->stream->bytes_served += len;
2359
                break;
2360
            }
2361
        }
2362
    } /* for(;;) */
2363
    return 0;
2364
}
2365

    
2366
static int http_start_receive_data(HTTPContext *c)
2367
{
2368
    int fd;
2369

    
2370
    if (c->stream->feed_opened)
2371
        return -1;
2372

    
2373
    /* Don't permit writing to this one */
2374
    if (c->stream->readonly)
2375
        return -1;
2376

    
2377
    /* open feed */
2378
    fd = open(c->stream->feed_filename, O_RDWR);
2379
    if (fd < 0)
2380
        return -1;
2381
    c->feed_fd = fd;
2382

    
2383
    c->stream->feed_write_index = ffm_read_write_index(fd);
2384
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2385
    lseek(fd, 0, SEEK_SET);
2386

    
2387
    /* init buffer input */
2388
    c->buffer_ptr = c->buffer;
2389
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2390
    c->stream->feed_opened = 1;
2391
    return 0;
2392
}
2393

    
2394
static int http_receive_data(HTTPContext *c)
2395
{
2396
    HTTPContext *c1;
2397

    
2398
    if (c->buffer_end > c->buffer_ptr) {
2399
        int len;
2400

    
2401
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2402
        if (len < 0) {
2403
            if (errno != EAGAIN && errno != EINTR) {
2404
                /* error : close connection */
2405
                goto fail;
2406
            }
2407
        } else if (len == 0) {
2408
            /* end of connection : close it */
2409
            goto fail;
2410
        } else {
2411
            c->buffer_ptr += len;
2412
            c->data_count += len;
2413
            update_datarate(&c->datarate, c->data_count);
2414
        }
2415
    }
2416

    
2417
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2418
        if (c->buffer[0] != 'f' ||
2419
            c->buffer[1] != 'm') {
2420
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2421
            goto fail;
2422
        }
2423
    }
2424

    
2425
    if (c->buffer_ptr >= c->buffer_end) {
2426
        FFStream *feed = c->stream;
2427
        /* a packet has been received : write it in the store, except
2428
           if header */
2429
        if (c->data_count > FFM_PACKET_SIZE) {
2430

    
2431
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2432
            /* XXX: use llseek or url_seek */
2433
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2434
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2435

    
2436
            feed->feed_write_index += FFM_PACKET_SIZE;
2437
            /* update file size */
2438
            if (feed->feed_write_index > c->stream->feed_size)
2439
                feed->feed_size = feed->feed_write_index;
2440

    
2441
            /* handle wrap around if max file size reached */
2442
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2443
                feed->feed_write_index = FFM_PACKET_SIZE;
2444

    
2445
            /* write index */
2446
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2447

    
2448
            /* wake up any waiting connections */
2449
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2450
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2451
                    c1->stream->feed == c->stream->feed) {
2452
                    c1->state = HTTPSTATE_SEND_DATA;
2453
                }
2454
            }
2455
        } else {
2456
            /* We have a header in our hands that contains useful data */
2457
            AVFormatContext s;
2458
            AVInputFormat *fmt_in;
2459
            ByteIOContext *pb = &s.pb;
2460
            int i;
2461

    
2462
            memset(&s, 0, sizeof(s));
2463

    
2464
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2465
            pb->buf_end = c->buffer_end;        /* ?? */
2466
            pb->is_streamed = 1;
2467

    
2468
            /* use feed output format name to find corresponding input format */
2469
            fmt_in = av_find_input_format(feed->fmt->name);
2470
            if (!fmt_in)
2471
                goto fail;
2472

    
2473
            if (fmt_in->priv_data_size > 0) {
2474
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2475
                if (!s.priv_data)
2476
                    goto fail;
2477
            } else
2478
                s.priv_data = NULL;
2479

    
2480
            if (fmt_in->read_header(&s, 0) < 0) {
2481
                av_freep(&s.priv_data);
2482
                goto fail;
2483
            }
2484

    
2485
            /* Now we have the actual streams */
2486
            if (s.nb_streams != feed->nb_streams) {
2487
                av_freep(&s.priv_data);
2488
                goto fail;
2489
            }
2490
            for (i = 0; i < s.nb_streams; i++) {
2491
                memcpy(feed->streams[i]->codec,
2492
                       s.streams[i]->codec, sizeof(AVCodecContext));
2493
            }
2494
            av_freep(&s.priv_data);
2495
        }
2496
        c->buffer_ptr = c->buffer;
2497
    }
2498

    
2499
    return 0;
2500
 fail:
2501
    c->stream->feed_opened = 0;
2502
    close(c->feed_fd);
2503
    return -1;
2504
}
2505

    
2506
/********************************************************************/
2507
/* RTSP handling */
2508

    
2509
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2510
{
2511
    const char *str;
2512
    time_t ti;
2513
    char *p;
2514
    char buf2[32];
2515

    
2516
    switch(error_number) {
2517
#define DEF(n, c, s) case c: str = s; break;
2518
#include "rtspcodes.h"
2519
#undef DEF
2520
    default:
2521
        str = "Unknown Error";
2522
        break;
2523
    }
2524

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

    
2528
    /* output GMT time */
2529
    ti = time(NULL);
2530
    p = ctime(&ti);
2531
    strcpy(buf2, p);
2532
    p = buf2 + strlen(p) - 1;
2533
    if (*p == '\n')
2534
        *p = '\0';
2535
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2536
}
2537

    
2538
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2539
{
2540
    rtsp_reply_header(c, error_number);
2541
    url_fprintf(c->pb, "\r\n");
2542
}
2543

    
2544
static int rtsp_parse_request(HTTPContext *c)
2545
{
2546
    const char *p, *p1, *p2;
2547
    char cmd[32];
2548
    char url[1024];
2549
    char protocol[32];
2550
    char line[1024];
2551
    ByteIOContext pb1;
2552
    int len;
2553
    RTSPHeader header1, *header = &header1;
2554

    
2555
    c->buffer_ptr[0] = '\0';
2556
    p = c->buffer;
2557

    
2558
    get_word(cmd, sizeof(cmd), &p);
2559
    get_word(url, sizeof(url), &p);
2560
    get_word(protocol, sizeof(protocol), &p);
2561

    
2562
    pstrcpy(c->method, sizeof(c->method), cmd);
2563
    pstrcpy(c->url, sizeof(c->url), url);
2564
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2565

    
2566
    c->pb = &pb1;
2567
    if (url_open_dyn_buf(c->pb) < 0) {
2568
        /* XXX: cannot do more */
2569
        c->pb = NULL; /* safety */
2570
        return -1;
2571
    }
2572

    
2573
    /* check version name */
2574
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2575
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2576
        goto the_end;
2577
    }
2578

    
2579
    /* parse each header line */
2580
    memset(header, 0, sizeof(RTSPHeader));
2581
    /* skip to next line */
2582
    while (*p != '\n' && *p != '\0')
2583
        p++;
2584
    if (*p == '\n')
2585
        p++;
2586
    while (*p != '\0') {
2587
        p1 = strchr(p, '\n');
2588
        if (!p1)
2589
            break;
2590
        p2 = p1;
2591
        if (p2 > p && p2[-1] == '\r')
2592
            p2--;
2593
        /* skip empty line */
2594
        if (p2 == p)
2595
            break;
2596
        len = p2 - p;
2597
        if (len > sizeof(line) - 1)
2598
            len = sizeof(line) - 1;
2599
        memcpy(line, p, len);
2600
        line[len] = '\0';
2601
        rtsp_parse_line(header, line);
2602
        p = p1 + 1;
2603
    }
2604

    
2605
    /* handle sequence number */
2606
    c->seq = header->seq;
2607

    
2608
    if (!strcmp(cmd, "DESCRIBE")) {
2609
        rtsp_cmd_describe(c, url);
2610
    } else if (!strcmp(cmd, "OPTIONS")) {
2611
        rtsp_cmd_options(c, url);
2612
    } else if (!strcmp(cmd, "SETUP")) {
2613
        rtsp_cmd_setup(c, url, header);
2614
    } else if (!strcmp(cmd, "PLAY")) {
2615
        rtsp_cmd_play(c, url, header);
2616
    } else if (!strcmp(cmd, "PAUSE")) {
2617
        rtsp_cmd_pause(c, url, header);
2618
    } else if (!strcmp(cmd, "TEARDOWN")) {
2619
        rtsp_cmd_teardown(c, url, header);
2620
    } else {
2621
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2622
    }
2623
 the_end:
2624
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2625
    c->pb = NULL; /* safety */
2626
    if (len < 0) {
2627
        /* XXX: cannot do more */
2628
        return -1;
2629
    }
2630
    c->buffer_ptr = c->pb_buffer;
2631
    c->buffer_end = c->pb_buffer + len;
2632
    c->state = RTSPSTATE_SEND_REPLY;
2633
    return 0;
2634
}
2635

    
2636
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2637
   AVFormatContext */
2638
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2639
                                   struct in_addr my_ip)
2640
{
2641
    ByteIOContext pb1, *pb = &pb1;
2642
    int i, payload_type, port, private_payload_type, j;
2643
    const char *ipstr, *title, *mediatype;
2644
    AVStream *st;
2645

    
2646
    if (url_open_dyn_buf(pb) < 0)
2647
        return -1;
2648

    
2649
    /* general media info */
2650

    
2651
    url_fprintf(pb, "v=0\n");
2652
    ipstr = inet_ntoa(my_ip);
2653
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2654
    title = stream->title;
2655
    if (title[0] == '\0')
2656
        title = "No Title";
2657
    url_fprintf(pb, "s=%s\n", title);
2658
    if (stream->comment[0] != '\0')
2659
        url_fprintf(pb, "i=%s\n", stream->comment);
2660
    if (stream->is_multicast) {
2661
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2662
    }
2663
    /* for each stream, we output the necessary info */
2664
    private_payload_type = RTP_PT_PRIVATE;
2665
    for(i = 0; i < stream->nb_streams; i++) {
2666
        st = stream->streams[i];
2667
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2668
            mediatype = "video";
2669
        } else {
2670
            switch(st->codec->codec_type) {
2671
            case CODEC_TYPE_AUDIO:
2672
                mediatype = "audio";
2673
                break;
2674
            case CODEC_TYPE_VIDEO:
2675
                mediatype = "video";
2676
                break;
2677
            default:
2678
                mediatype = "application";
2679
                break;
2680
            }
2681
        }
2682
        /* NOTE: the port indication is not correct in case of
2683
           unicast. It is not an issue because RTSP gives it */
2684
        payload_type = rtp_get_payload_type(st->codec);
2685
        if (payload_type < 0)
2686
            payload_type = private_payload_type++;
2687
        if (stream->is_multicast) {
2688
            port = stream->multicast_port + 2 * i;
2689
        } else {
2690
            port = 0;
2691
        }
2692
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2693
                    mediatype, port, payload_type);
2694
        if (payload_type >= RTP_PT_PRIVATE) {
2695
            /* for private payload type, we need to give more info */
2696
            switch(st->codec->codec_id) {
2697
            case CODEC_ID_MPEG4:
2698
                {
2699
                    uint8_t *data;
2700
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2701
                                payload_type, 90000);
2702
                    /* we must also add the mpeg4 header */
2703
                    data = st->codec->extradata;
2704
                    if (data) {
2705
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2706
                        for(j=0;j<st->codec->extradata_size;j++) {
2707
                            url_fprintf(pb, "%02x", data[j]);
2708
                        }
2709
                        url_fprintf(pb, "\n");
2710
                    }
2711
                }
2712
                break;
2713
            default:
2714
                /* XXX: add other codecs ? */
2715
                goto fail;
2716
            }
2717
        }
2718
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2719
    }
2720
    return url_close_dyn_buf(pb, pbuffer);
2721
 fail:
2722
    url_close_dyn_buf(pb, pbuffer);
2723
    av_free(*pbuffer);
2724
    return -1;
2725
}
2726

    
2727
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2728
{
2729
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2730
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2731
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2732
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2733
    url_fprintf(c->pb, "\r\n");
2734
}
2735

    
2736
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2737
{
2738
    FFStream *stream;
2739
    char path1[1024];
2740
    const char *path;
2741
    uint8_t *content;
2742
    int content_length, len;
2743
    struct sockaddr_in my_addr;
2744

    
2745
    /* find which url is asked */
2746
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2747
    path = path1;
2748
    if (*path == '/')
2749
        path++;
2750

    
2751
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2752
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2753
            !strcmp(path, stream->filename)) {
2754
            goto found;
2755
        }
2756
    }
2757
    /* no stream found */
2758
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2759
    return;
2760

    
2761
 found:
2762
    /* prepare the media description in sdp format */
2763

    
2764
    /* get the host IP */
2765
    len = sizeof(my_addr);
2766
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2767
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2768
    if (content_length < 0) {
2769
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2770
        return;
2771
    }
2772
    rtsp_reply_header(c, RTSP_STATUS_OK);
2773
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2774
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2775
    url_fprintf(c->pb, "\r\n");
2776
    put_buffer(c->pb, content, content_length);
2777
}
2778

    
2779
static HTTPContext *find_rtp_session(const char *session_id)
2780
{
2781
    HTTPContext *c;
2782

    
2783
    if (session_id[0] == '\0')
2784
        return NULL;
2785

    
2786
    for(c = first_http_ctx; c != NULL; c = c->next) {
2787
        if (!strcmp(c->session_id, session_id))
2788
            return c;
2789
    }
2790
    return NULL;
2791
}
2792

    
2793
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2794
{
2795
    RTSPTransportField *th;
2796
    int i;
2797

    
2798
    for(i=0;i<h->nb_transports;i++) {
2799
        th = &h->transports[i];
2800
        if (th->protocol == protocol)
2801
            return th;
2802
    }
2803
    return NULL;
2804
}
2805

    
2806
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2807
                           RTSPHeader *h)
2808
{
2809
    FFStream *stream;
2810
    int stream_index, port;
2811
    char buf[1024];
2812
    char path1[1024];
2813
    const char *path;
2814
    HTTPContext *rtp_c;
2815
    RTSPTransportField *th;
2816
    struct sockaddr_in dest_addr;
2817
    RTSPActionServerSetup setup;
2818

    
2819
    /* find which url is asked */
2820
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2821
    path = path1;
2822
    if (*path == '/')
2823
        path++;
2824

    
2825
    /* now check each stream */
2826
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2827
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2828
            /* accept aggregate filenames only if single stream */
2829
            if (!strcmp(path, stream->filename)) {
2830
                if (stream->nb_streams != 1) {
2831
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2832
                    return;
2833
                }
2834
                stream_index = 0;
2835
                goto found;
2836
            }
2837

    
2838
            for(stream_index = 0; stream_index < stream->nb_streams;
2839
                stream_index++) {
2840
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2841
                         stream->filename, stream_index);
2842
                if (!strcmp(path, buf))
2843
                    goto found;
2844
            }
2845
        }
2846
    }
2847
    /* no stream found */
2848
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2849
    return;
2850
 found:
2851

    
2852
    /* generate session id if needed */
2853
    if (h->session_id[0] == '\0') {
2854
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2855
                 av_random(&random_state), av_random(&random_state));
2856
    }
2857

    
2858
    /* find rtp session, and create it if none found */
2859
    rtp_c = find_rtp_session(h->session_id);
2860
    if (!rtp_c) {
2861
        /* always prefer UDP */
2862
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2863
        if (!th) {
2864
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2865
            if (!th) {
2866
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2867
                return;
2868
            }
2869
        }
2870

    
2871
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2872
                                   th->protocol);
2873
        if (!rtp_c) {
2874
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2875
            return;
2876
        }
2877

    
2878
        /* open input stream */
2879
        if (open_input_stream(rtp_c, "") < 0) {
2880
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2881
            return;
2882
        }
2883
    }
2884

    
2885
    /* test if stream is OK (test needed because several SETUP needs
2886
       to be done for a given file) */
2887
    if (rtp_c->stream != stream) {
2888
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2889
        return;
2890
    }
2891

    
2892
    /* test if stream is already set up */
2893
    if (rtp_c->rtp_ctx[stream_index]) {
2894
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2895
        return;
2896
    }
2897

    
2898
    /* check transport */
2899
    th = find_transport(h, rtp_c->rtp_protocol);
2900
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2901
                th->client_port_min <= 0)) {
2902
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2903
        return;
2904
    }
2905

    
2906
    /* setup default options */
2907
    setup.transport_option[0] = '\0';
2908
    dest_addr = rtp_c->from_addr;
2909
    dest_addr.sin_port = htons(th->client_port_min);
2910

    
2911
    /* add transport option if needed */
2912
    if (ff_rtsp_callback) {
2913
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2914
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2915
                             (char *)&setup, sizeof(setup),
2916
                             stream->rtsp_option) < 0) {
2917
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2918
            return;
2919
        }
2920
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2921
    }
2922

    
2923
    /* setup stream */
2924
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2925
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2926
        return;
2927
    }
2928

    
2929
    /* now everything is OK, so we can send the connection parameters */
2930
    rtsp_reply_header(c, RTSP_STATUS_OK);
2931
    /* session ID */
2932
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2933

    
2934
    switch(rtp_c->rtp_protocol) {
2935
    case RTSP_PROTOCOL_RTP_UDP:
2936
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2937
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2938
                    "client_port=%d-%d;server_port=%d-%d",
2939
                    th->client_port_min, th->client_port_min + 1,
2940
                    port, port + 1);
2941
        break;
2942
    case RTSP_PROTOCOL_RTP_TCP:
2943
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2944
                    stream_index * 2, stream_index * 2 + 1);
2945
        break;
2946
    default:
2947
        break;
2948
    }
2949
    if (setup.transport_option[0] != '\0') {
2950
        url_fprintf(c->pb, ";%s", setup.transport_option);
2951
    }
2952
    url_fprintf(c->pb, "\r\n");
2953

    
2954

    
2955
    url_fprintf(c->pb, "\r\n");
2956
}
2957

    
2958

    
2959
/* find an rtp connection by using the session ID. Check consistency
2960
   with filename */
2961
static HTTPContext *find_rtp_session_with_url(const char *url,
2962
                                              const char *session_id)
2963
{
2964
    HTTPContext *rtp_c;
2965
    char path1[1024];
2966
    const char *path;
2967
    char buf[1024];
2968
    int s;
2969

    
2970
    rtp_c = find_rtp_session(session_id);
2971
    if (!rtp_c)
2972
        return NULL;
2973

    
2974
    /* find which url is asked */
2975
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2976
    path = path1;
2977
    if (*path == '/')
2978
        path++;
2979
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2980
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2981
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2982
        rtp_c->stream->filename, s);
2983
      if(!strncmp(path, buf, sizeof(buf))) {
2984
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2985
        return rtp_c;
2986
      }
2987
    }
2988
    return NULL;
2989
}
2990

    
2991
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2992
{
2993
    HTTPContext *rtp_c;
2994

    
2995
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2996
    if (!rtp_c) {
2997
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2998
        return;
2999
    }
3000

    
3001
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3002
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3003
        rtp_c->state != HTTPSTATE_READY) {
3004
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3005
        return;
3006
    }
3007

    
3008
#if 0
3009
    /* XXX: seek in stream */
3010
    if (h->range_start != AV_NOPTS_VALUE) {
3011
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3012
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3013
    }
3014
#endif
3015

    
3016
    rtp_c->state = HTTPSTATE_SEND_DATA;
3017

    
3018
    /* now everything is OK, so we can send the connection parameters */
3019
    rtsp_reply_header(c, RTSP_STATUS_OK);
3020
    /* session ID */
3021
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3022
    url_fprintf(c->pb, "\r\n");
3023
}
3024

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

    
3029
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3030
    if (!rtp_c) {
3031
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3032
        return;
3033
    }
3034

    
3035
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3036
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3037
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3038
        return;
3039
    }
3040

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

    
3050
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3051
{
3052
    HTTPContext *rtp_c;
3053

    
3054
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3055
    if (!rtp_c) {
3056
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3057
        return;
3058
    }
3059

    
3060
    /* abort the session */
3061
    close_connection(rtp_c);
3062

    
3063
    if (ff_rtsp_callback) {
3064
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3065
                         NULL, 0,
3066
                         rtp_c->stream->rtsp_option);
3067
    }
3068

    
3069
    /* now everything is OK, so we can send the connection parameters */
3070
    rtsp_reply_header(c, RTSP_STATUS_OK);
3071
    /* session ID */
3072
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3073
    url_fprintf(c->pb, "\r\n");
3074
}
3075

    
3076

    
3077
/********************************************************************/
3078
/* RTP handling */
3079

    
3080
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3081
                                       FFStream *stream, const char *session_id,
3082
                                       enum RTSPProtocol rtp_protocol)
3083
{
3084
    HTTPContext *c = NULL;
3085
    const char *proto_str;
3086

    
3087
    /* XXX: should output a warning page when coming
3088
       close to the connection limit */
3089
    if (nb_connections >= nb_max_connections)
3090
        goto fail;
3091

    
3092
    /* add a new connection */
3093
    c = av_mallocz(sizeof(HTTPContext));
3094
    if (!c)
3095
        goto fail;
3096

    
3097
    c->fd = -1;
3098
    c->poll_entry = NULL;
3099
    c->from_addr = *from_addr;
3100
    c->buffer_size = IOBUFFER_INIT_SIZE;
3101
    c->buffer = av_malloc(c->buffer_size);
3102
    if (!c->buffer)
3103
        goto fail;
3104
    nb_connections++;
3105
    c->stream = stream;
3106
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3107
    c->state = HTTPSTATE_READY;
3108
    c->is_packetized = 1;
3109
    c->rtp_protocol = rtp_protocol;
3110

    
3111
    /* protocol is shown in statistics */
3112
    switch(c->rtp_protocol) {
3113
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3114
        proto_str = "MCAST";
3115
        break;
3116
    case RTSP_PROTOCOL_RTP_UDP:
3117
        proto_str = "UDP";
3118
        break;
3119
    case RTSP_PROTOCOL_RTP_TCP:
3120
        proto_str = "TCP";
3121
        break;
3122
    default:
3123
        proto_str = "???";
3124
        break;
3125
    }
3126
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3127
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3128

    
3129
    current_bandwidth += stream->bandwidth;
3130

    
3131
    c->next = first_http_ctx;
3132
    first_http_ctx = c;
3133
    return c;
3134

    
3135
 fail:
3136
    if (c) {
3137
        av_free(c->buffer);
3138
        av_free(c);
3139
    }
3140
    return NULL;
3141
}
3142

    
3143
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3144
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3145
   used. */
3146
static int rtp_new_av_stream(HTTPContext *c,
3147
                             int stream_index, struct sockaddr_in *dest_addr,
3148
                             HTTPContext *rtsp_c)
3149
{
3150
    AVFormatContext *ctx;
3151
    AVStream *st;
3152
    char *ipaddr;
3153
    URLContext *h;
3154
    uint8_t *dummy_buf;
3155
    char buf2[32];
3156
    int max_packet_size;
3157

    
3158
    /* now we can open the relevant output stream */
3159
    ctx = av_alloc_format_context();
3160
    if (!ctx)
3161
        return -1;
3162
    ctx->oformat = &rtp_muxer;
3163

    
3164
    st = av_mallocz(sizeof(AVStream));
3165
    if (!st)
3166
        goto fail;
3167
    st->codec= avcodec_alloc_context();
3168
    ctx->nb_streams = 1;
3169
    ctx->streams[0] = st;
3170

    
3171
    if (!c->stream->feed ||
3172
        c->stream->feed == c->stream) {
3173
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3174
    } else {
3175
        memcpy(st,
3176
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3177
               sizeof(AVStream));
3178
    }
3179

    
3180
    /* build destination RTP address */
3181
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3182

    
3183
    switch(c->rtp_protocol) {
3184
    case RTSP_PROTOCOL_RTP_UDP:
3185
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3186
        /* RTP/UDP case */
3187

    
3188
        /* XXX: also pass as parameter to function ? */
3189
        if (c->stream->is_multicast) {
3190
            int ttl;
3191
            ttl = c->stream->multicast_ttl;
3192
            if (!ttl)
3193
                ttl = 16;
3194
            snprintf(ctx->filename, sizeof(ctx->filename),
3195
                     "rtp://%s:%d?multicast=1&ttl=%d",
3196
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3197
        } else {
3198
            snprintf(ctx->filename, sizeof(ctx->filename),
3199
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3200
        }
3201

    
3202
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3203
            goto fail;
3204
        c->rtp_handles[stream_index] = h;
3205
        max_packet_size = url_get_max_packet_size(h);
3206
        break;
3207
    case RTSP_PROTOCOL_RTP_TCP:
3208
        /* RTP/TCP case */
3209
        c->rtsp_c = rtsp_c;
3210
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3211
        break;
3212
    default:
3213
        goto fail;
3214
    }
3215

    
3216
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3217
             ipaddr, ntohs(dest_addr->sin_port),
3218
             ctime1(buf2),
3219
             c->stream->filename, stream_index, c->protocol);
3220

    
3221
    /* normally, no packets should be output here, but the packet size may be checked */
3222
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3223
        /* XXX: close stream */
3224
        goto fail;
3225
    }
3226
    av_set_parameters(ctx, NULL);
3227
    if (av_write_header(ctx) < 0) {
3228
    fail:
3229
        if (h)
3230
            url_close(h);
3231
        av_free(ctx);
3232
        return -1;
3233
    }
3234
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3235
    av_free(dummy_buf);
3236

    
3237
    c->rtp_ctx[stream_index] = ctx;
3238
    return 0;
3239
}
3240

    
3241
/********************************************************************/
3242
/* ffserver initialization */
3243

    
3244
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3245
{
3246
    AVStream *fst;
3247

    
3248
    fst = av_mallocz(sizeof(AVStream));
3249
    if (!fst)
3250
        return NULL;
3251
    fst->codec= avcodec_alloc_context();
3252
    fst->priv_data = av_mallocz(sizeof(FeedData));
3253
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3254
    fst->codec->coded_frame = &dummy_frame;
3255
    fst->index = stream->nb_streams;
3256
    av_set_pts_info(fst, 33, 1, 90000);
3257
    stream->streams[stream->nb_streams++] = fst;
3258
    return fst;
3259
}
3260

    
3261
/* return the stream number in the feed */
3262
static int add_av_stream(FFStream *feed, AVStream *st)
3263
{
3264
    AVStream *fst;
3265
    AVCodecContext *av, *av1;
3266
    int i;
3267

    
3268
    av = st->codec;
3269
    for(i=0;i<feed->nb_streams;i++) {
3270
        st = feed->streams[i];
3271
        av1 = st->codec;
3272
        if (av1->codec_id == av->codec_id &&
3273
            av1->codec_type == av->codec_type &&
3274
            av1->bit_rate == av->bit_rate) {
3275

    
3276
            switch(av->codec_type) {
3277
            case CODEC_TYPE_AUDIO:
3278
                if (av1->channels == av->channels &&
3279
                    av1->sample_rate == av->sample_rate)
3280
                    goto found;
3281
                break;
3282
            case CODEC_TYPE_VIDEO:
3283
                if (av1->width == av->width &&
3284
                    av1->height == av->height &&
3285
                    av1->time_base.den == av->time_base.den &&
3286
                    av1->time_base.num == av->time_base.num &&
3287
                    av1->gop_size == av->gop_size)
3288
                    goto found;
3289
                break;
3290
            default:
3291
                av_abort();
3292
            }
3293
        }
3294
    }
3295

    
3296
    fst = add_av_stream1(feed, av);
3297
    if (!fst)
3298
        return -1;
3299
    return feed->nb_streams - 1;
3300
 found:
3301
    return i;
3302
}
3303

    
3304
static void remove_stream(FFStream *stream)
3305
{
3306
    FFStream **ps;
3307
    ps = &first_stream;
3308
    while (*ps != NULL) {
3309
        if (*ps == stream) {
3310
            *ps = (*ps)->next;
3311
        } else {
3312
            ps = &(*ps)->next;
3313
        }
3314
    }
3315
}
3316

    
3317
/* specific mpeg4 handling : we extract the raw parameters */
3318
static void extract_mpeg4_header(AVFormatContext *infile)
3319
{
3320
    int mpeg4_count, i, size;
3321
    AVPacket pkt;
3322
    AVStream *st;
3323
    const uint8_t *p;
3324

    
3325
    mpeg4_count = 0;
3326
    for(i=0;i<infile->nb_streams;i++) {
3327
        st = infile->streams[i];
3328
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3329
            st->codec->extradata_size == 0) {
3330
            mpeg4_count++;
3331
        }
3332
    }
3333
    if (!mpeg4_count)
3334
        return;
3335

    
3336
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3337
    while (mpeg4_count > 0) {
3338
        if (av_read_packet(infile, &pkt) < 0)
3339
            break;
3340
        st = infile->streams[pkt.stream_index];
3341
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3342
            st->codec->extradata_size == 0) {
3343
            av_freep(&st->codec->extradata);
3344
            /* fill extradata with the header */
3345
            /* XXX: we make hard suppositions here ! */
3346
            p = pkt.data;
3347
            while (p < pkt.data + pkt.size - 4) {
3348
                /* stop when vop header is found */
3349
                if (p[0] == 0x00 && p[1] == 0x00 &&
3350
                    p[2] == 0x01 && p[3] == 0xb6) {
3351
                    size = p - pkt.data;
3352
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3353
                    st->codec->extradata = av_malloc(size);
3354
                    st->codec->extradata_size = size;
3355
                    memcpy(st->codec->extradata, pkt.data, size);
3356
                    break;
3357
                }
3358
                p++;
3359
            }
3360
            mpeg4_count--;
3361
        }
3362
        av_free_packet(&pkt);
3363
    }
3364
}
3365

    
3366
/* compute the needed AVStream for each file */
3367
static void build_file_streams(void)
3368
{
3369
    FFStream *stream, *stream_next;
3370
    AVFormatContext *infile;
3371
    int i;
3372

    
3373
    /* gather all streams */
3374
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3375
        stream_next = stream->next;
3376
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3377
            !stream->feed) {
3378
            /* the stream comes from a file */
3379
            /* try to open the file */
3380
            /* open stream */
3381
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3382
            if (stream->fmt == &rtp_muxer) {
3383
                /* specific case : if transport stream output to RTP,
3384
                   we use a raw transport stream reader */
3385
                stream->ap_in->mpeg2ts_raw = 1;
3386
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3387
            }
3388

    
3389
            if (av_open_input_file(&infile, stream->feed_filename,
3390
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3391
                http_log("%s not found", stream->feed_filename);
3392
                /* remove stream (no need to spend more time on it) */
3393
            fail:
3394
                remove_stream(stream);
3395
            } else {
3396
                /* find all the AVStreams inside and reference them in
3397
                   'stream' */
3398
                if (av_find_stream_info(infile) < 0) {
3399
                    http_log("Could not find codec parameters from '%s'",
3400
                             stream->feed_filename);
3401
                    av_close_input_file(infile);
3402
                    goto fail;
3403
                }
3404
                extract_mpeg4_header(infile);
3405

    
3406
                for(i=0;i<infile->nb_streams;i++) {
3407
                    add_av_stream1(stream, infile->streams[i]->codec);
3408
                }
3409
                av_close_input_file(infile);
3410
            }
3411
        }
3412
    }
3413
}
3414

    
3415
/* compute the needed AVStream for each feed */
3416
static void build_feed_streams(void)
3417
{
3418
    FFStream *stream, *feed;
3419
    int i;
3420

    
3421
    /* gather all streams */
3422
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3423
        feed = stream->feed;
3424
        if (feed) {
3425
            if (!stream->is_feed) {
3426
                /* we handle a stream coming from a feed */
3427
                for(i=0;i<stream->nb_streams;i++) {
3428
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3429
                }
3430
            }
3431
        }
3432
    }
3433

    
3434
    /* gather all streams */
3435
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3436
        feed = stream->feed;
3437
        if (feed) {
3438
            if (stream->is_feed) {
3439
                for(i=0;i<stream->nb_streams;i++) {
3440
                    stream->feed_streams[i] = i;
3441
                }
3442
            }
3443
        }
3444
    }
3445

    
3446
    /* create feed files if needed */
3447
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3448
        int fd;
3449

    
3450
        if (url_exist(feed->feed_filename)) {
3451
            /* See if it matches */
3452
            AVFormatContext *s;
3453
            int matches = 0;
3454

    
3455
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3456
                /* Now see if it matches */
3457
                if (s->nb_streams == feed->nb_streams) {
3458
                    matches = 1;
3459
                    for(i=0;i<s->nb_streams;i++) {
3460
                        AVStream *sf, *ss;
3461
                        sf = feed->streams[i];
3462
                        ss = s->streams[i];
3463

    
3464
                        if (sf->index != ss->index ||
3465
                            sf->id != ss->id) {
3466
                            printf("Index & Id do not match for stream %d (%s)\n",
3467
                                   i, feed->feed_filename);
3468
                            matches = 0;
3469
                        } else {
3470
                            AVCodecContext *ccf, *ccs;
3471

    
3472
                            ccf = sf->codec;
3473
                            ccs = ss->codec;
3474
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3475

    
3476
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3477
                                printf("Codecs do not match for stream %d\n", i);
3478
                                matches = 0;
3479
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3480
                                printf("Codec bitrates do not match for stream %d\n", i);
3481
                                matches = 0;
3482
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3483
                                if (CHECK_CODEC(time_base.den) ||
3484
                                    CHECK_CODEC(time_base.num) ||
3485
                                    CHECK_CODEC(width) ||
3486
                                    CHECK_CODEC(height)) {
3487
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3488
                                    matches = 0;
3489
                                }
3490
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3491
                                if (CHECK_CODEC(sample_rate) ||
3492
                                    CHECK_CODEC(channels) ||
3493
                                    CHECK_CODEC(frame_size)) {
3494
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3495
                                    matches = 0;
3496
                                }
3497
                            } else {
3498
                                printf("Unknown codec type\n");
3499
                                matches = 0;
3500
                            }
3501
                        }
3502
                        if (!matches) {
3503
                            break;
3504
                        }
3505
                    }
3506
                } else {
3507
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3508
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3509
                }
3510

    
3511
                av_close_input_file(s);
3512
            } else {
3513
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3514
                        feed->feed_filename);
3515
            }
3516
            if (!matches) {
3517
                if (feed->readonly) {
3518
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3519
                        feed->feed_filename);
3520
                    exit(1);
3521
                }
3522
                unlink(feed->feed_filename);
3523
            }
3524
        }
3525
        if (!url_exist(feed->feed_filename)) {
3526
            AVFormatContext s1, *s = &s1;
3527

    
3528
            if (feed->readonly) {
3529
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3530
                    feed->feed_filename);
3531
                exit(1);
3532
            }
3533

    
3534
            /* only write the header of the ffm file */
3535
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3536
                fprintf(stderr, "Could not open output feed file '%s'\n",
3537
                        feed->feed_filename);
3538
                exit(1);
3539
            }
3540
            s->oformat = feed->fmt;
3541
            s->nb_streams = feed->nb_streams;
3542
            for(i=0;i<s->nb_streams;i++) {
3543
                AVStream *st;
3544
                st = feed->streams[i];
3545
                s->streams[i] = st;
3546
            }
3547
            av_set_parameters(s, NULL);
3548
            if (av_write_header(s) < 0) {
3549
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3550
                exit(1);
3551
            }
3552
            /* XXX: need better api */
3553
            av_freep(&s->priv_data);
3554
            url_fclose(&s->pb);
3555
        }
3556
        /* get feed size and write index */
3557
        fd = open(feed->feed_filename, O_RDONLY);
3558
        if (fd < 0) {
3559
            fprintf(stderr, "Could not open output feed file '%s'\n",
3560
                    feed->feed_filename);
3561
            exit(1);
3562
        }
3563

    
3564
        feed->feed_write_index = ffm_read_write_index(fd);
3565
        feed->feed_size = lseek(fd, 0, SEEK_END);
3566
        /* ensure that we do not wrap before the end of file */
3567
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3568
            feed->feed_max_size = feed->feed_size;
3569

    
3570
        close(fd);
3571
    }
3572
}
3573

    
3574
/* compute the bandwidth used by each stream */
3575
static void compute_bandwidth(void)
3576
{
3577
    int bandwidth, i;
3578
    FFStream *stream;
3579

    
3580
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3581
        bandwidth = 0;
3582
        for(i=0;i<stream->nb_streams;i++) {
3583
            AVStream *st = stream->streams[i];
3584
            switch(st->codec->codec_type) {
3585
            case CODEC_TYPE_AUDIO:
3586
            case CODEC_TYPE_VIDEO:
3587
                bandwidth += st->codec->bit_rate;
3588
                break;
3589
            default:
3590
                break;
3591
            }
3592
        }
3593
        stream->bandwidth = (bandwidth + 999) / 1000;
3594
    }
3595
}
3596

    
3597
static void get_arg(char *buf, int buf_size, const char **pp)
3598
{
3599
    const char *p;
3600
    char *q;
3601
    int quote;
3602

    
3603
    p = *pp;
3604
    while (isspace(*p)) p++;
3605
    q = buf;
3606
    quote = 0;
3607
    if (*p == '\"' || *p == '\'')
3608
        quote = *p++;
3609
    for(;;) {
3610
        if (quote) {
3611
            if (*p == quote)
3612
                break;
3613
        } else {
3614
            if (isspace(*p))
3615
                break;
3616
        }
3617
        if (*p == '\0')
3618
            break;
3619
        if ((q - buf) < buf_size - 1)
3620
            *q++ = *p;
3621
        p++;
3622
    }
3623
    *q = '\0';
3624
    if (quote && *p == quote)
3625
        p++;
3626
    *pp = p;
3627
}
3628

    
3629
/* add a codec and set the default parameters */
3630
static void add_codec(FFStream *stream, AVCodecContext *av)
3631
{
3632
    AVStream *st;
3633

    
3634
    /* compute default parameters */
3635
    switch(av->codec_type) {
3636
    case CODEC_TYPE_AUDIO:
3637
        if (av->bit_rate == 0)
3638
            av->bit_rate = 64000;
3639
        if (av->sample_rate == 0)
3640
            av->sample_rate = 22050;
3641
        if (av->channels == 0)
3642
            av->channels = 1;
3643
        break;
3644
    case CODEC_TYPE_VIDEO:
3645
        if (av->bit_rate == 0)
3646
            av->bit_rate = 64000;
3647
        if (av->time_base.num == 0){
3648
            av->time_base.den = 5;
3649
            av->time_base.num = 1;
3650
        }
3651
        if (av->width == 0 || av->height == 0) {
3652
            av->width = 160;
3653
            av->height = 128;
3654
        }
3655
        /* Bitrate tolerance is less for streaming */
3656
        if (av->bit_rate_tolerance == 0)
3657
            av->bit_rate_tolerance = av->bit_rate / 4;
3658
        if (av->qmin == 0)
3659
            av->qmin = 3;
3660
        if (av->qmax == 0)
3661
            av->qmax = 31;
3662
        if (av->max_qdiff == 0)
3663
            av->max_qdiff = 3;
3664
        av->qcompress = 0.5;
3665
        av->qblur = 0.5;
3666

    
3667
        if (!av->nsse_weight)
3668
            av->nsse_weight = 8;
3669

    
3670
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3671
        av->me_method = ME_EPZS;
3672
        av->rc_buffer_aggressivity = 1.0;
3673

    
3674
        if (!av->rc_eq)
3675
            av->rc_eq = "tex^qComp";
3676
        if (!av->i_quant_factor)
3677
            av->i_quant_factor = -0.8;
3678
        if (!av->b_quant_factor)
3679
            av->b_quant_factor = 1.25;
3680
        if (!av->b_quant_offset)
3681
            av->b_quant_offset = 1.25;
3682
        if (!av->rc_max_rate)
3683
            av->rc_max_rate = av->bit_rate * 2;
3684

    
3685
        if (av->rc_max_rate && !av->rc_buffer_size) {
3686
            av->rc_buffer_size = av->rc_max_rate;
3687
        }
3688

    
3689

    
3690
        break;
3691
    default:
3692
        av_abort();
3693
    }
3694

    
3695
    st = av_mallocz(sizeof(AVStream));
3696
    if (!st)
3697
        return;
3698
    st->codec = avcodec_alloc_context();
3699
    stream->streams[stream->nb_streams++] = st;
3700
    memcpy(st->codec, av, sizeof(AVCodecContext));
3701
}
3702

    
3703
static int opt_audio_codec(const char *arg)
3704
{
3705
    AVCodec *p;
3706

    
3707
    p = first_avcodec;
3708
    while (p) {
3709
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3710
            break;
3711
        p = p->next;
3712
    }
3713
    if (p == NULL) {
3714
        return CODEC_ID_NONE;
3715
    }
3716

    
3717
    return p->id;
3718
}
3719

    
3720
static int opt_video_codec(const char *arg)
3721
{
3722
    AVCodec *p;
3723

    
3724
    p = first_avcodec;
3725
    while (p) {
3726
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3727
            break;
3728
        p = p->next;
3729
    }
3730
    if (p == NULL) {
3731
        return CODEC_ID_NONE;
3732
    }
3733

    
3734
    return p->id;
3735
}
3736

    
3737
/* simplistic plugin support */
3738

    
3739
#ifdef HAVE_DLOPEN
3740
static void load_module(const char *filename)
3741
{
3742
    void *dll;
3743
    void (*init_func)(void);
3744
    dll = dlopen(filename, RTLD_NOW);
3745
    if (!dll) {
3746
        fprintf(stderr, "Could not load module '%s' - %s\n",
3747
                filename, dlerror());
3748
        return;
3749
    }
3750

    
3751
    init_func = dlsym(dll, "ffserver_module_init");
3752
    if (!init_func) {
3753
        fprintf(stderr,
3754
                "%s: init function 'ffserver_module_init()' not found\n",
3755
                filename);
3756
        dlclose(dll);
3757
    }
3758

    
3759
    init_func();
3760
}
3761
#endif
3762

    
3763
static int parse_ffconfig(const char *filename)
3764
{
3765
    FILE *f;
3766
    char line[1024];
3767
    char cmd[64];
3768
    char arg[1024];
3769
    const char *p;
3770
    int val, errors, line_num;
3771
    FFStream **last_stream, *stream, *redirect;
3772
    FFStream **last_feed, *feed;
3773
    AVCodecContext audio_enc, video_enc;
3774
    int audio_id, video_id;
3775

    
3776
    f = fopen(filename, "r");
3777
    if (!f) {
3778
        perror(filename);
3779
        return -1;
3780
    }
3781

    
3782
    errors = 0;
3783
    line_num = 0;
3784
    first_stream = NULL;
3785
    last_stream = &first_stream;
3786
    first_feed = NULL;
3787
    last_feed = &first_feed;
3788
    stream = NULL;
3789
    feed = NULL;
3790
    redirect = NULL;
3791
    audio_id = CODEC_ID_NONE;
3792
    video_id = CODEC_ID_NONE;
3793
    for(;;) {
3794
        if (fgets(line, sizeof(line), f) == NULL)
3795
            break;
3796
        line_num++;
3797
        p = line;
3798
        while (isspace(*p))
3799
            p++;
3800
        if (*p == '\0' || *p == '#')
3801
            continue;
3802

    
3803
        get_arg(cmd, sizeof(cmd), &p);
3804

    
3805
        if (!strcasecmp(cmd, "Port")) {
3806
            get_arg(arg, sizeof(arg), &p);
3807
            my_http_addr.sin_port = htons (atoi(arg));
3808
        } else if (!strcasecmp(cmd, "BindAddress")) {
3809
            get_arg(arg, sizeof(arg), &p);
3810
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3811
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3812
                        filename, line_num, arg);
3813
                errors++;
3814
            }
3815
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3816
            ffserver_daemon = 0;
3817
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3818
            get_arg(arg, sizeof(arg), &p);
3819
            my_rtsp_addr.sin_port = htons (atoi(arg));
3820
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3821
            get_arg(arg, sizeof(arg), &p);
3822
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3823
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3824
                        filename, line_num, arg);
3825
                errors++;
3826
            }
3827
        } else if (!strcasecmp(cmd, "MaxClients")) {
3828
            get_arg(arg, sizeof(arg), &p);
3829
            val = atoi(arg);
3830
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3831
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3832
                        filename, line_num, arg);
3833
                errors++;
3834
            } else {
3835
                nb_max_connections = val;
3836
            }
3837
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3838
            get_arg(arg, sizeof(arg), &p);
3839
            val = atoi(arg);
3840
            if (val < 10 || val > 100000) {
3841
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3842
                        filename, line_num, arg);
3843
                errors++;
3844
            } else {
3845
                max_bandwidth = val;
3846
            }
3847
        } else if (!strcasecmp(cmd, "CustomLog")) {
3848
            get_arg(logfilename, sizeof(logfilename), &p);
3849
        } else if (!strcasecmp(cmd, "<Feed")) {
3850
            /*********************************************/
3851
            /* Feed related options */
3852
            char *q;
3853
            if (stream || feed) {
3854
                fprintf(stderr, "%s:%d: Already in a tag\n",
3855
                        filename, line_num);
3856
            } else {
3857
                feed = av_mallocz(sizeof(FFStream));
3858
                /* add in stream list */
3859
                *last_stream = feed;
3860
                last_stream = &feed->next;
3861
                /* add in feed list */
3862
                *last_feed = feed;
3863
                last_feed = &feed->next_feed;
3864

    
3865
                get_arg(feed->filename, sizeof(feed->filename), &p);
3866
                q = strrchr(feed->filename, '>');
3867
                if (*q)
3868
                    *q = '\0';
3869
                feed->fmt = guess_format("ffm", NULL, NULL);
3870
                /* defaut feed file */
3871
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3872
                         "/tmp/%s.ffm", feed->filename);
3873
                feed->feed_max_size = 5 * 1024 * 1024;
3874
                feed->is_feed = 1;
3875
                feed->feed = feed; /* self feeding :-) */
3876
            }
3877
        } else if (!strcasecmp(cmd, "Launch")) {
3878
            if (feed) {
3879
                int i;
3880

    
3881
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3882

    
3883
                for (i = 0; i < 62; i++) {
3884
                    char argbuf[256];
3885

    
3886
                    get_arg(argbuf, sizeof(argbuf), &p);
3887
                    if (!argbuf[0])
3888
                        break;
3889

    
3890
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3891
                    strcpy(feed->child_argv[i], argbuf);
3892
                }
3893

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

    
3896
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3897
                    "http://%s:%d/%s",
3898
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3899
                    inet_ntoa(my_http_addr.sin_addr),
3900
                    ntohs(my_http_addr.sin_port), feed->filename);
3901

    
3902
                if (ffserver_debug)
3903
                {
3904
                    int j;
3905
                    fprintf(stdout, "Launch commandline: ");
3906
                    for (j = 0; j <= i; j++)
3907
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3908
                    fprintf(stdout, "\n");
3909
                }
3910
            }
3911
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3912
            if (feed) {
3913
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3914
                feed->readonly = 1;
3915
            } else if (stream) {
3916
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3917
            }
3918
        } else if (!strcasecmp(cmd, "File")) {
3919
            if (feed) {
3920
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3921
            } else if (stream) {
3922
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3923
            }
3924
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3925
            if (feed) {
3926
                const char *p1;
3927
                double fsize;
3928

    
3929
                get_arg(arg, sizeof(arg), &p);
3930
                p1 = arg;
3931
                fsize = strtod(p1, (char **)&p1);
3932
                switch(toupper(*p1)) {
3933
                case 'K':
3934
                    fsize *= 1024;
3935
                    break;
3936
                case 'M':
3937
                    fsize *= 1024 * 1024;
3938
                    break;
3939
                case 'G':
3940
                    fsize *= 1024 * 1024 * 1024;
3941
                    break;
3942
                }
3943
                feed->feed_max_size = (int64_t)fsize;
3944
            }
3945
        } else if (!strcasecmp(cmd, "</Feed>")) {
3946
            if (!feed) {
3947
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3948
                        filename, line_num);
3949
                errors++;
3950
#if 0
3951
            } else {
3952
                /* Make sure that we start out clean */
3953
                if (unlink(feed->feed_filename) < 0
3954
                    && errno != ENOENT) {
3955
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3956
                        filename, line_num, feed->feed_filename, strerror(errno));
3957
                    errors++;
3958
                }
3959
#endif
3960
            }
3961
            feed = NULL;
3962
        } else if (!strcasecmp(cmd, "<Stream")) {
3963
            /*********************************************/
3964
            /* Stream related options */
3965
            char *q;
3966
            if (stream || feed) {
3967
                fprintf(stderr, "%s:%d: Already in a tag\n",
3968
                        filename, line_num);
3969
            } else {
3970
                stream = av_mallocz(sizeof(FFStream));
3971
                *last_stream = stream;
3972
                last_stream = &stream->next;
3973

    
3974
                get_arg(stream->filename, sizeof(stream->filename), &p);
3975
                q = strrchr(stream->filename, '>');
3976
                if (*q)
3977
                    *q = '\0';
3978
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3979
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3980
                memset(&video_enc, 0, sizeof(AVCodecContext));
3981
                audio_id = CODEC_ID_NONE;
3982
                video_id = CODEC_ID_NONE;
3983
                if (stream->fmt) {
3984
                    audio_id = stream->fmt->audio_codec;
3985
                    video_id = stream->fmt->video_codec;
3986
                }
3987
            }
3988
        } else if (!strcasecmp(cmd, "Feed")) {
3989
            get_arg(arg, sizeof(arg), &p);
3990
            if (stream) {
3991
                FFStream *sfeed;
3992

    
3993
                sfeed = first_feed;
3994
                while (sfeed != NULL) {
3995
                    if (!strcmp(sfeed->filename, arg))
3996
                        break;
3997
                    sfeed = sfeed->next_feed;
3998
                }
3999
                if (!sfeed) {
4000
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4001
                            filename, line_num, arg);
4002
                } else {
4003
                    stream->feed = sfeed;
4004
                }
4005
            }
4006
        } else if (!strcasecmp(cmd, "Format")) {
4007
            get_arg(arg, sizeof(arg), &p);
4008
            if (!strcmp(arg, "status")) {
4009
                stream->stream_type = STREAM_TYPE_STATUS;
4010
                stream->fmt = NULL;
4011
            } else {
4012
                stream->stream_type = STREAM_TYPE_LIVE;
4013
                /* jpeg cannot be used here, so use single frame jpeg */
4014
                if (!strcmp(arg, "jpeg"))
4015
                    strcpy(arg, "mjpeg");
4016
                stream->fmt = guess_stream_format(arg, NULL, NULL);
4017
                if (!stream->fmt) {
4018
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4019
                            filename, line_num, arg);
4020
                    errors++;
4021
                }
4022
            }
4023
            if (stream->fmt) {
4024
                audio_id = stream->fmt->audio_codec;
4025
                video_id = stream->fmt->video_codec;
4026
            }
4027
        } else if (!strcasecmp(cmd, "InputFormat")) {
4028
            stream->ifmt = av_find_input_format(arg);
4029
            if (!stream->ifmt) {
4030
                fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4031
                        filename, line_num, arg);
4032
            }
4033
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4034
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4035
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4036
            } else {
4037
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4038
                            filename, line_num);
4039
                errors++;
4040
            }
4041
        } else if (!strcasecmp(cmd, "Author")) {
4042
            if (stream) {
4043
                get_arg(stream->author, sizeof(stream->author), &p);
4044
            }
4045
        } else if (!strcasecmp(cmd, "Comment")) {
4046
            if (stream) {
4047
                get_arg(stream->comment, sizeof(stream->comment), &p);
4048
            }
4049
        } else if (!strcasecmp(cmd, "Copyright")) {
4050
            if (stream) {
4051
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4052
            }
4053
        } else if (!strcasecmp(cmd, "Title")) {
4054
            if (stream) {
4055
                get_arg(stream->title, sizeof(stream->title), &p);
4056
            }
4057
        } else if (!strcasecmp(cmd, "Preroll")) {
4058
            get_arg(arg, sizeof(arg), &p);
4059
            if (stream) {
4060
                stream->prebuffer = atof(arg) * 1000;
4061
            }
4062
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4063
            if (stream) {
4064
                stream->send_on_key = 1;
4065
            }
4066
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4067
            get_arg(arg, sizeof(arg), &p);
4068
            audio_id = opt_audio_codec(arg);
4069
            if (audio_id == CODEC_ID_NONE) {
4070
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4071
                        filename, line_num, arg);
4072
                errors++;
4073
            }
4074
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4075
            get_arg(arg, sizeof(arg), &p);
4076
            video_id = opt_video_codec(arg);
4077
            if (video_id == CODEC_ID_NONE) {
4078
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4079
                        filename, line_num, arg);
4080
                errors++;
4081
            }
4082
        } else if (!strcasecmp(cmd, "MaxTime")) {
4083
            get_arg(arg, sizeof(arg), &p);
4084
            if (stream) {
4085
                stream->max_time = atof(arg) * 1000;
4086
            }
4087
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4088
            get_arg(arg, sizeof(arg), &p);
4089
            if (stream) {
4090
                audio_enc.bit_rate = atoi(arg) * 1000;
4091
            }
4092
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4093
            get_arg(arg, sizeof(arg), &p);
4094
            if (stream) {
4095
                audio_enc.channels = atoi(arg);
4096
            }
4097
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4098
            get_arg(arg, sizeof(arg), &p);
4099
            if (stream) {
4100
                audio_enc.sample_rate = atoi(arg);
4101
            }
4102
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4103
            get_arg(arg, sizeof(arg), &p);
4104
            if (stream) {
4105
//                audio_enc.quality = atof(arg) * 1000;
4106
            }
4107
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4108
            if (stream) {
4109
                int minrate, maxrate;
4110

    
4111
                get_arg(arg, sizeof(arg), &p);
4112

    
4113
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4114
                    video_enc.rc_min_rate = minrate * 1000;
4115
                    video_enc.rc_max_rate = maxrate * 1000;
4116
                } else {
4117
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4118
                            filename, line_num, arg);
4119
                    errors++;
4120
                }
4121
            }
4122
        } else if (!strcasecmp(cmd, "Debug")) {
4123
            if (stream) {
4124
                get_arg(arg, sizeof(arg), &p);
4125
                video_enc.debug = strtol(arg,0,0);
4126
            }
4127
        } else if (!strcasecmp(cmd, "Strict")) {
4128
            if (stream) {
4129
                get_arg(arg, sizeof(arg), &p);
4130
                video_enc.strict_std_compliance = atoi(arg);
4131
            }
4132
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4133
            if (stream) {
4134
                get_arg(arg, sizeof(arg), &p);
4135
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4136
            }
4137
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4138
            if (stream) {
4139
                get_arg(arg, sizeof(arg), &p);
4140
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4141
            }
4142
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4143
            get_arg(arg, sizeof(arg), &p);
4144
            if (stream) {
4145
                video_enc.bit_rate = atoi(arg) * 1000;
4146
            }
4147
        } else if (!strcasecmp(cmd, "VideoSize")) {
4148
            get_arg(arg, sizeof(arg), &p);
4149
            if (stream) {
4150
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4151
                if ((video_enc.width % 16) != 0 ||
4152
                    (video_enc.height % 16) != 0) {
4153
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4154
                            filename, line_num);
4155
                    errors++;
4156
                }
4157
            }
4158
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4159
            get_arg(arg, sizeof(arg), &p);
4160
            if (stream) {
4161
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4162
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4163
            }
4164
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4165
            get_arg(arg, sizeof(arg), &p);
4166
            if (stream) {
4167
                video_enc.gop_size = atoi(arg);
4168
            }
4169
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4170
            if (stream) {
4171
                video_enc.gop_size = 1;
4172
            }
4173
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4174
            if (stream) {
4175
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4176
            }
4177
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4178
            if (stream) {
4179
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4180
                video_enc.flags |= CODEC_FLAG_4MV;
4181
            }
4182
        } else if (!strcasecmp(cmd, "VideoTag")) {
4183
            get_arg(arg, sizeof(arg), &p);
4184
            if ((strlen(arg) == 4) && stream) {
4185
                video_enc.codec_tag = ff_get_fourcc(arg);
4186
            }
4187
        } else if (!strcasecmp(cmd, "BitExact")) {
4188
            if (stream) {
4189
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4190
            }
4191
        } else if (!strcasecmp(cmd, "DctFastint")) {
4192
            if (stream) {
4193
                video_enc.dct_algo  = FF_DCT_FASTINT;
4194
            }
4195
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4196
            if (stream) {
4197
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4198
            }
4199
        } else if (!strcasecmp(cmd, "Qscale")) {
4200
            get_arg(arg, sizeof(arg), &p);
4201
            if (stream) {
4202
                video_enc.flags |= CODEC_FLAG_QSCALE;
4203
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4204
            }
4205
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4206
            get_arg(arg, sizeof(arg), &p);
4207
            if (stream) {
4208
                video_enc.max_qdiff = atoi(arg);
4209
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4210
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4211
                            filename, line_num);
4212
                    errors++;
4213
                }
4214
            }
4215
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4216
            get_arg(arg, sizeof(arg), &p);
4217
            if (stream) {
4218
                video_enc.qmax = atoi(arg);
4219
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4220
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4221
                            filename, line_num);
4222
                    errors++;
4223
                }
4224
            }
4225
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4226
            get_arg(arg, sizeof(arg), &p);
4227
            if (stream) {
4228
                video_enc.qmin = atoi(arg);
4229
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4230
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4231
                            filename, line_num);
4232
                    errors++;
4233
                }
4234
            }
4235
        } else if (!strcasecmp(cmd, "LumaElim")) {
4236
            get_arg(arg, sizeof(arg), &p);
4237
            if (stream) {
4238
                video_enc.luma_elim_threshold = atoi(arg);
4239
            }
4240
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4241
            get_arg(arg, sizeof(arg), &p);
4242
            if (stream) {
4243
                video_enc.chroma_elim_threshold = atoi(arg);
4244
            }
4245
        } else if (!strcasecmp(cmd, "LumiMask")) {
4246
            get_arg(arg, sizeof(arg), &p);
4247
            if (stream) {
4248
                video_enc.lumi_masking = atof(arg);
4249
            }
4250
        } else if (!strcasecmp(cmd, "DarkMask")) {
4251
            get_arg(arg, sizeof(arg), &p);
4252
            if (stream) {
4253
                video_enc.dark_masking = atof(arg);
4254
            }
4255
        } else if (!strcasecmp(cmd, "NoVideo")) {
4256
            video_id = CODEC_ID_NONE;
4257
        } else if (!strcasecmp(cmd, "NoAudio")) {
4258
            audio_id = CODEC_ID_NONE;
4259
        } else if (!strcasecmp(cmd, "ACL")) {
4260
            IPAddressACL acl;
4261
            struct hostent *he;
4262

    
4263
            get_arg(arg, sizeof(arg), &p);
4264
            if (strcasecmp(arg, "allow") == 0) {
4265
                acl.action = IP_ALLOW;
4266
            } else if (strcasecmp(arg, "deny") == 0) {
4267
                acl.action = IP_DENY;
4268
            } else {
4269
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4270
                        filename, line_num, arg);
4271
                errors++;
4272
            }
4273

    
4274
            get_arg(arg, sizeof(arg), &p);
4275

    
4276
            he = gethostbyname(arg);
4277
            if (!he) {
4278
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4279
                        filename, line_num, arg);
4280
                errors++;
4281
            } else {
4282
                /* Only take the first */
4283
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4284
                acl.last = acl.first;
4285
            }
4286

    
4287
            get_arg(arg, sizeof(arg), &p);
4288

    
4289
            if (arg[0]) {
4290
                he = gethostbyname(arg);
4291
                if (!he) {
4292
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4293
                            filename, line_num, arg);
4294
                    errors++;
4295
                } else {
4296
                    /* Only take the first */
4297
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4298
                }
4299
            }
4300

    
4301
            if (!errors) {
4302
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4303
                IPAddressACL **naclp = 0;
4304

    
4305
                *nacl = acl;
4306
                nacl->next = 0;
4307

    
4308
                if (stream) {
4309
                    naclp = &stream->acl;
4310
                } else if (feed) {
4311
                    naclp = &feed->acl;
4312
                } else {
4313
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4314
                            filename, line_num);
4315
                    errors++;
4316
                }
4317

    
4318
                if (naclp) {
4319
                    while (*naclp)
4320
                        naclp = &(*naclp)->next;
4321

    
4322
                    *naclp = nacl;
4323
                }
4324
            }
4325
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4326
            get_arg(arg, sizeof(arg), &p);
4327
            if (stream) {
4328
                av_freep(&stream->rtsp_option);
4329
                /* XXX: av_strdup ? */
4330
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4331
                if (stream->rtsp_option) {
4332
                    strcpy(stream->rtsp_option, arg);
4333
                }
4334
            }
4335
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4336
            get_arg(arg, sizeof(arg), &p);
4337
            if (stream) {
4338
                if (!inet_aton(arg, &stream->multicast_ip)) {
4339
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
4340
                            filename, line_num, arg);
4341
                    errors++;
4342
                }
4343
                stream->is_multicast = 1;
4344
                stream->loop = 1; /* default is looping */
4345
            }
4346
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4347
            get_arg(arg, sizeof(arg), &p);
4348
            if (stream) {
4349
                stream->multicast_port = atoi(arg);
4350
            }
4351
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4352
            get_arg(arg, sizeof(arg), &p);
4353
            if (stream) {
4354
                stream->multicast_ttl = atoi(arg);
4355
            }
4356
        } else if (!strcasecmp(cmd, "NoLoop")) {
4357
            if (stream) {
4358
                stream->loop = 0;
4359
            }
4360
        } else if (!strcasecmp(cmd, "</Stream>")) {
4361
            if (!stream) {
4362
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4363
                        filename, line_num);
4364
                errors++;
4365
            }
4366
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4367
                if (audio_id != CODEC_ID_NONE) {
4368
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4369
                    audio_enc.codec_id = audio_id;
4370
                    add_codec(stream, &audio_enc);
4371
                }
4372
                if (video_id != CODEC_ID_NONE) {
4373
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4374
                    video_enc.codec_id = video_id;
4375
                    add_codec(stream, &video_enc);
4376
                }
4377
            }
4378
            stream = NULL;
4379
        } else if (!strcasecmp(cmd, "<Redirect")) {
4380
            /*********************************************/
4381
            char *q;
4382
            if (stream || feed || redirect) {
4383
                fprintf(stderr, "%s:%d: Already in a tag\n",
4384
                        filename, line_num);
4385
                errors++;
4386
            } else {
4387
                redirect = av_mallocz(sizeof(FFStream));
4388
                *last_stream = redirect;
4389
                last_stream = &redirect->next;
4390

    
4391
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4392
                q = strrchr(redirect->filename, '>');
4393
                if (*q)
4394
                    *q = '\0';
4395
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4396
            }
4397
        } else if (!strcasecmp(cmd, "URL")) {
4398
            if (redirect) {
4399
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4400
            }
4401
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4402
            if (!redirect) {
4403
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4404
                        filename, line_num);
4405
                errors++;
4406
            }
4407
            if (!redirect->feed_filename[0]) {
4408
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4409
                        filename, line_num);
4410
                errors++;
4411
            }
4412
            redirect = NULL;
4413
        } else if (!strcasecmp(cmd, "LoadModule")) {
4414
            get_arg(arg, sizeof(arg), &p);
4415
#ifdef HAVE_DLOPEN
4416
            load_module(arg);
4417
#else
4418
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4419
                    filename, line_num, arg);
4420
            errors++;
4421
#endif
4422
        } else {
4423
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4424
                    filename, line_num, cmd);
4425
            errors++;
4426
        }
4427
    }
4428

    
4429
    fclose(f);
4430
    if (errors)
4431
        return -1;
4432
    else
4433
        return 0;
4434
}
4435

    
4436

    
4437
#if 0
4438
static void write_packet(FFCodec *ffenc,
4439
                         uint8_t *buf, int size)
4440
{
4441
    PacketHeader hdr;
4442
    AVCodecContext *enc = &ffenc->enc;
4443
    uint8_t *wptr;
4444
    mk_header(&hdr, enc, size);
4445
    wptr = http_fifo.wptr;
4446
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4447
    fifo_write(&http_fifo, buf, size, &wptr);
4448
    /* atomic modification of wptr */
4449
    http_fifo.wptr = wptr;
4450
    ffenc->data_count += size;
4451
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4452
}
4453
#endif
4454

    
4455
static void show_banner(void)
4456
{
4457
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4458
}
4459

    
4460
static void show_help(void)
4461
{
4462
    show_banner();
4463
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4464
           "Hyper fast multi format Audio/Video streaming server\n"
4465
           "\n"
4466
           "-L            : print the LICENSE\n"
4467
           "-h            : this help\n"
4468
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4469
           );
4470
}
4471

    
4472
static void show_license(void)
4473
{
4474
    show_banner();
4475
    printf(
4476
    "FFmpeg is free software; you can redistribute it and/or\n"
4477
    "modify it under the terms of the GNU Lesser General Public\n"
4478
    "License as published by the Free Software Foundation; either\n"
4479
    "version 2.1 of the License, or (at your option) any later version.\n"
4480
    "\n"
4481
    "FFmpeg is distributed in the hope that it will be useful,\n"
4482
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4483
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4484
    "Lesser General Public License for more details.\n"
4485
    "\n"
4486
    "You should have received a copy of the GNU Lesser General Public\n"
4487
    "License along with FFmpeg; if not, write to the Free Software\n"
4488
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4489
    );
4490
}
4491

    
4492
static void handle_child_exit(int sig)
4493
{
4494
    pid_t pid;
4495
    int status;
4496

    
4497
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4498
        FFStream *feed;
4499

    
4500
        for (feed = first_feed; feed; feed = feed->next) {
4501
            if (feed->pid == pid) {
4502
                int uptime = time(0) - feed->pid_start;
4503

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

    
4507
                if (uptime < 30) {
4508
                    /* Turn off any more restarts */
4509
                    feed->child_argv = 0;
4510
                }
4511
            }
4512
        }
4513
    }
4514

    
4515
    need_to_start_children = 1;
4516
}
4517

    
4518
int main(int argc, char **argv)
4519
{
4520
    const char *config_filename;
4521
    int c;
4522
    struct sigaction sigact;
4523

    
4524
    av_register_all();
4525

    
4526
    config_filename = "/etc/ffserver.conf";
4527

    
4528
    my_program_name = argv[0];
4529
    my_program_dir = getcwd(0, 0);
4530
    ffserver_daemon = 1;
4531

    
4532
    for(;;) {
4533
        c = getopt(argc, argv, "ndLh?f:");
4534
        if (c == -1)
4535
            break;
4536
        switch(c) {
4537
        case 'L':
4538
            show_license();
4539
            exit(1);
4540
        case '?':
4541
        case 'h':
4542
            show_help();
4543
            exit(1);
4544
        case 'n':
4545
            no_launch = 1;
4546
            break;
4547
        case 'd':
4548
            ffserver_debug = 1;
4549
            ffserver_daemon = 0;
4550
            break;
4551
        case 'f':
4552
            config_filename = optarg;
4553
            break;
4554
        default:
4555
            exit(2);
4556
        }
4557
    }
4558

    
4559
    putenv("http_proxy");               /* Kill the http_proxy */
4560

    
4561
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4562

    
4563
    /* address on which the server will handle HTTP connections */
4564
    my_http_addr.sin_family = AF_INET;
4565
    my_http_addr.sin_port = htons (8080);
4566
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4567

    
4568
    /* address on which the server will handle RTSP connections */
4569
    my_rtsp_addr.sin_family = AF_INET;
4570
    my_rtsp_addr.sin_port = htons (5454);
4571
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4572

    
4573
    nb_max_connections = 5;
4574
    max_bandwidth = 1000;
4575
    first_stream = NULL;
4576
    logfilename[0] = '\0';
4577

    
4578
    memset(&sigact, 0, sizeof(sigact));
4579
    sigact.sa_handler = handle_child_exit;
4580
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4581
    sigaction(SIGCHLD, &sigact, 0);
4582

    
4583
    if (parse_ffconfig(config_filename) < 0) {
4584
        fprintf(stderr, "Incorrect config file - exiting.\n");
4585
        exit(1);
4586
    }
4587

    
4588
    build_file_streams();
4589

    
4590
    build_feed_streams();
4591

    
4592
    compute_bandwidth();
4593

    
4594
    /* put the process in background and detach it from its TTY */
4595
    if (ffserver_daemon) {
4596
        int pid;
4597

    
4598
        pid = fork();
4599
        if (pid < 0) {
4600
            perror("fork");
4601
            exit(1);
4602
        } else if (pid > 0) {
4603
            /* parent : exit */
4604
            exit(0);
4605
        } else {
4606
            /* child */
4607
            setsid();
4608
            chdir("/");
4609
            close(0);
4610
            open("/dev/null", O_RDWR);
4611
            if (strcmp(logfilename, "-") != 0) {
4612
                close(1);
4613
                dup(0);
4614
            }
4615
            close(2);
4616
            dup(0);
4617
        }
4618
    }
4619

    
4620
    /* signal init */
4621
    signal(SIGPIPE, SIG_IGN);
4622

    
4623
    /* open log file if needed */
4624
    if (logfilename[0] != '\0') {
4625
        if (!strcmp(logfilename, "-"))
4626
            logfile = stdout;
4627
        else
4628
            logfile = fopen(logfilename, "w");
4629
    }
4630

    
4631
    if (http_server() < 0) {
4632
        fprintf(stderr, "Could not start server\n");
4633
        exit(1);
4634
    }
4635

    
4636
    return 0;
4637
}