Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 638831aa

History | View | Annotate | Download (151 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
/* maximum number of simultaneous HTTP connections */
51
#define HTTP_MAX_CONNECTIONS 2000
52

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

    
63
    RTSPSTATE_WAIT_REQUEST,
64
    RTSPSTATE_SEND_REPLY,
65
    RTSPSTATE_SEND_PACKET,
66
};
67

    
68
const char *http_state[] = {
69
    "HTTP_WAIT_REQUEST",
70
    "HTTP_SEND_HEADER",
71

    
72
    "SEND_DATA_HEADER",
73
    "SEND_DATA",
74
    "SEND_DATA_TRAILER",
75
    "RECEIVE_DATA",
76
    "WAIT_FEED",
77
    "READY",
78

    
79
    "RTSP_WAIT_REQUEST",
80
    "RTSP_SEND_REPLY",
81
    "RTSP_SEND_PACKET",
82
};
83

    
84
#define IOBUFFER_INIT_SIZE 8192
85

    
86
/* coef for exponential mean for bitrate estimation in statistics */
87
#define AVG_COEF 0.9
88

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

    
93
#define SYNC_TIMEOUT (10 * 1000)
94

    
95
typedef struct {
96
    int64_t count1, count2;
97
    long time1, time2;
98
} DataRateData;
99

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

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

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

    
155
    /* RTP/UDP specific */
156
    URLContext *rtp_handles[MAX_STREAMS];
157

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

    
163
static AVFrame dummy_frame;
164

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

    
172
enum IPAddressAction {
173
    IP_ALLOW = 1,
174
    IP_DENY,
175
};
176

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

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

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

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

    
238
struct sockaddr_in my_http_addr;
239
struct sockaddr_in my_rtsp_addr;
240

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

    
246
static void new_connection(int server_fd, int is_rtsp);
247
static void close_connection(HTTPContext *c);
248

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

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

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

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

    
279
static const char *my_program_name;
280
static const char *my_program_dir;
281

    
282
static int ffserver_debug;
283
static int ffserver_daemon;
284
static int no_launch;
285
static int need_to_start_children;
286

    
287
static int nb_max_connections;
288
static int nb_connections;
289

    
290
static int max_bandwidth;
291
static int current_bandwidth;
292

    
293
static long cur_time;           // Making this global saves on passing it around everywhere
294

    
295
static AVRandomState random_state;
296

    
297
static FILE *logfile = NULL;
298

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

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

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

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

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

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

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

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

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

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

    
362

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

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

    
372
            feed->pid = fork();
373

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

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

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

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

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

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

    
411
                signal(SIGPIPE, SIG_DFL);
412

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

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

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

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

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

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

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

    
450
    return server_fd;
451
}
452

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

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

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

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

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

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

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

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

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

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

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

    
525
    start_children(first_feed);
526

    
527
    first_http_ctx = NULL;
528
    nb_connections = 0;
529

    
530
    start_multicast();
531

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

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

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

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

    
600
        cur_time = (long)(av_gettime()/1000);
601

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

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

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

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

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

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

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

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

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

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

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

    
680
    start_wait_request(c, is_rtsp);
681

    
682
    return;
683

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

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

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

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

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

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

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

    
748
    ctx = &c->fmt_ctx;
749

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

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

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

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

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

    
779
static int handle_connection(HTTPContext *c)
780
{
781
    int len, ret;
782

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

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

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

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

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

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

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

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

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

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

    
961
            while (*q && *q != '\n' && isspace(*q))
962
                q++;
963

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

    
968
                q += 20;
969

    
970
                memset(rates, 0xff, ratelen);
971

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

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

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

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

    
995
        p++;
996
    }
997

    
998
    return 0;
999
}
1000

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

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

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

    
1017
        /* Potential stream */
1018

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

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

    
1036
    return best;
1037
}
1038

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

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

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

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

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

    
1074
    return action_required;
1075
}
1076

    
1077

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1206
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1207

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

    
1211
    /* find the filename and the optional info string in the request */
1212
    p = url;
1213
    if (*p == '/')
1214
        p++;
1215
    filename = p;
1216
    p = strchr(p, '?');
1217
    if (p) {
1218
        pstrcpy(info, sizeof(info), p);
1219
        *p = '\0';
1220
    } else {
1221
        info[0] = '\0';
1222
    }
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(url) - 1);
1252
    } else if (match_ext(filename, "sdp")) {
1253
        redir_type = REDIR_SDP;
1254
        compute_real_filename(filename, sizeof(url) - 1);
1255
    }
1256

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

    
1268
    c->stream = stream;
1269
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1270
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1271

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

    
1283
        /* prepare output buffer */
1284
        c->buffer_ptr = c->buffer;
1285
        c->buffer_end = q;
1286
        c->state = HTTPSTATE_SEND_HEADER;
1287
        return 0;
1288
    }
1289

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

    
1300
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1301
        current_bandwidth += stream->bandwidth;
1302
    }
1303

    
1304
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1305
        c->http_error = 200;
1306
        q = c->buffer;
1307
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1308
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1309
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1310
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1311
        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");
1312
        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",
1313
            current_bandwidth, max_bandwidth);
1314
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1315

    
1316
        /* prepare output buffer */
1317
        c->buffer_ptr = c->buffer;
1318
        c->buffer_end = q;
1319
        c->state = HTTPSTATE_SEND_HEADER;
1320
        return 0;
1321
    }
1322

    
1323
    if (redir_type != REDIR_NONE) {
1324
        char *hostinfo = 0;
1325

    
1326
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1327
            if (strncasecmp(p, "Host:", 5) == 0) {
1328
                hostinfo = p + 5;
1329
                break;
1330
            }
1331
            p = strchr(p, '\n');
1332
            if (!p)
1333
                break;
1334

    
1335
            p++;
1336
        }
1337

    
1338
        if (hostinfo) {
1339
            char *eoh;
1340
            char hostbuf[260];
1341

    
1342
            while (isspace(*hostinfo))
1343
                hostinfo++;
1344

    
1345
            eoh = strchr(hostinfo, '\n');
1346
            if (eoh) {
1347
                if (eoh[-1] == '\r')
1348
                    eoh--;
1349

    
1350
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1351
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1352
                    hostbuf[eoh - hostinfo] = 0;
1353

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

    
1406
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1407
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1408
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1409

    
1410
                            len = sizeof(my_addr);
1411
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1412

    
1413
                            /* XXX: should use a dynamic buffer */
1414
                            sdp_data_size = prepare_sdp_description(stream,
1415
                                                                    &sdp_data,
1416
                                                                    my_addr.sin_addr);
1417
                            if (sdp_data_size > 0) {
1418
                                memcpy(q, sdp_data, sdp_data_size);
1419
                                q += sdp_data_size;
1420
                                *q = '\0';
1421
                                av_free(sdp_data);
1422
                            }
1423
                        }
1424
                        break;
1425
                    default:
1426
                        av_abort();
1427
                        break;
1428
                    }
1429

    
1430
                    /* prepare output buffer */
1431
                    c->buffer_ptr = c->buffer;
1432
                    c->buffer_end = q;
1433
                    c->state = HTTPSTATE_SEND_HEADER;
1434
                    return 0;
1435
                }
1436
            }
1437
        }
1438

    
1439
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1440
        goto send_error;
1441
    }
1442

    
1443
    stream->conns_served++;
1444

    
1445
    /* XXX: add there authenticate and IP match */
1446

    
1447
    if (c->post) {
1448
        /* if post, it means a feed is being sent */
1449
        if (!stream->is_feed) {
1450
            /* However it might be a status report from WMP! Lets log the data
1451
             * as it might come in handy one day
1452
             */
1453
            char *logline = 0;
1454
            int client_id = 0;
1455

    
1456
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1457
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1458
                    logline = p;
1459
                    break;
1460
                }
1461
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1462
                    client_id = strtol(p + 18, 0, 10);
1463
                }
1464
                p = strchr(p, '\n');
1465
                if (!p)
1466
                    break;
1467

    
1468
                p++;
1469
            }
1470

    
1471
            if (logline) {
1472
                char *eol = strchr(logline, '\n');
1473

    
1474
                logline += 17;
1475

    
1476
                if (eol) {
1477
                    if (eol[-1] == '\r')
1478
                        eol--;
1479
                    http_log("%.*s\n", (int) (eol - logline), logline);
1480
                    c->suppress_log = 1;
1481
                }
1482
            }
1483

    
1484
#ifdef DEBUG_WMP
1485
            http_log("\nGot request:\n%s\n", c->buffer);
1486
#endif
1487

    
1488
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1489
                HTTPContext *wmpc;
1490

    
1491
                /* Now we have to find the client_id */
1492
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1493
                    if (wmpc->wmp_client_id == client_id)
1494
                        break;
1495
                }
1496

    
1497
                if (wmpc) {
1498
                    if (modify_current_stream(wmpc, ratebuf)) {
1499
                        wmpc->switch_pending = 1;
1500
                    }
1501
                }
1502
            }
1503

    
1504
            snprintf(msg, sizeof(msg), "POST command not handled");
1505
            c->stream = 0;
1506
            goto send_error;
1507
        }
1508
        if (http_start_receive_data(c) < 0) {
1509
            snprintf(msg, sizeof(msg), "could not open feed");
1510
            goto send_error;
1511
        }
1512
        c->http_error = 0;
1513
        c->state = HTTPSTATE_RECEIVE_DATA;
1514
        return 0;
1515
    }
1516

    
1517
#ifdef DEBUG_WMP
1518
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1519
        http_log("\nGot request:\n%s\n", c->buffer);
1520
    }
1521
#endif
1522

    
1523
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1524
        goto send_stats;
1525

    
1526
    /* open input stream */
1527
    if (open_input_stream(c, info) < 0) {
1528
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1529
        goto send_error;
1530
    }
1531

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

    
1540
    /* for asf, we need extra headers */
1541
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1542
        /* Need to allocate a client id */
1543

    
1544
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1545

    
1546
        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);
1547
    }
1548
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1549
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1550

    
1551
    /* prepare output buffer */
1552
    c->http_error = 0;
1553
    c->buffer_ptr = c->buffer;
1554
    c->buffer_end = q;
1555
    c->state = HTTPSTATE_SEND_HEADER;
1556
    return 0;
1557
 send_error:
1558
    c->http_error = 404;
1559
    q = c->buffer;
1560
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1561
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1562
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1563
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1564
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1565
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1566
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1567

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

    
1581
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1582
{
1583
    static const char *suffix = " kMGTP";
1584
    const char *s;
1585

    
1586
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1587
    }
1588

    
1589
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1590
}
1591

    
1592
static void compute_stats(HTTPContext *c)
1593
{
1594
    HTTPContext *c1;
1595
    FFStream *stream;
1596
    char *p;
1597
    time_t ti;
1598
    int i, len;
1599
    ByteIOContext pb1, *pb = &pb1;
1600

    
1601
    if (url_open_dyn_buf(pb) < 0) {
1602
        /* XXX: return an error ? */
1603
        c->buffer_ptr = c->buffer;
1604
        c->buffer_end = c->buffer;
1605
        return;
1606
    }
1607

    
1608
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1609
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1610
    url_fprintf(pb, "Pragma: no-cache\r\n");
1611
    url_fprintf(pb, "\r\n");
1612

    
1613
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1614
    if (c->stream->feed_filename) {
1615
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1616
    }
1617
    url_fprintf(pb, "</HEAD>\n<BODY>");
1618
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1619
    /* format status */
1620
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1621
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1622
    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");
1623
    stream = first_stream;
1624
    while (stream != NULL) {
1625
        char sfilename[1024];
1626
        char *eosf;
1627

    
1628
        if (stream->feed != stream) {
1629
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1630
            eosf = sfilename + strlen(sfilename);
1631
            if (eosf - sfilename >= 4) {
1632
                if (strcmp(eosf - 4, ".asf") == 0) {
1633
                    strcpy(eosf - 4, ".asx");
1634
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1635
                    strcpy(eosf - 3, ".ram");
1636
                } else if (stream->fmt == &rtp_muxer) {
1637
                    /* generate a sample RTSP director if
1638
                       unicast. Generate an SDP redirector if
1639
                       multicast */
1640
                    eosf = strrchr(sfilename, '.');
1641
                    if (!eosf)
1642
                        eosf = sfilename + strlen(sfilename);
1643
                    if (stream->is_multicast)
1644
                        strcpy(eosf, ".sdp");
1645
                    else
1646
                        strcpy(eosf, ".rtsp");
1647
                }
1648
            }
1649

    
1650
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1651
                         sfilename, stream->filename);
1652
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1653
                        stream->conns_served);
1654
            fmt_bytecount(pb, stream->bytes_served);
1655
            switch(stream->stream_type) {
1656
            case STREAM_TYPE_LIVE:
1657
                {
1658
                    int audio_bit_rate = 0;
1659
                    int video_bit_rate = 0;
1660
                    const char *audio_codec_name = "";
1661
                    const char *video_codec_name = "";
1662
                    const char *audio_codec_name_extra = "";
1663
                    const char *video_codec_name_extra = "";
1664

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

    
1714
    stream = first_stream;
1715
    while (stream != NULL) {
1716
        if (stream->feed == stream) {
1717
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1718
            if (stream->pid) {
1719
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1720

    
1721
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1722
                {
1723
                    FILE *pid_stat;
1724
                    char ps_cmd[64];
1725

    
1726
                    /* This is somewhat linux specific I guess */
1727
                    snprintf(ps_cmd, sizeof(ps_cmd),
1728
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1729
                             stream->pid);
1730

    
1731
                    pid_stat = popen(ps_cmd, "r");
1732
                    if (pid_stat) {
1733
                        char cpuperc[10];
1734
                        char cpuused[64];
1735

    
1736
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1737
                                   cpuused) == 2) {
1738
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1739
                                         cpuperc, cpuused);
1740
                        }
1741
                        fclose(pid_stat);
1742
                    }
1743
                }
1744
#endif
1745

    
1746
                url_fprintf(pb, "<p>");
1747
            }
1748
            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");
1749

    
1750
            for (i = 0; i < stream->nb_streams; i++) {
1751
                AVStream *st = stream->streams[i];
1752
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1753
                const char *type = "unknown";
1754
                char parameters[64];
1755

    
1756
                parameters[0] = 0;
1757

    
1758
                switch(st->codec->codec_type) {
1759
                case CODEC_TYPE_AUDIO:
1760
                    type = "audio";
1761
                    break;
1762
                case CODEC_TYPE_VIDEO:
1763
                    type = "video";
1764
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1765
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1766
                    break;
1767
                default:
1768
                    av_abort();
1769
                }
1770
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1771
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1772
            }
1773
            url_fprintf(pb, "</table>\n");
1774

    
1775
        }
1776
        stream = stream->next;
1777
    }
1778

    
1779
#if 0
1780
    {
1781
        float avg;
1782
        AVCodecContext *enc;
1783
        char buf[1024];
1784

1785
        /* feed status */
1786
        stream = first_feed;
1787
        while (stream != NULL) {
1788
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1789
            url_fprintf(pb, "<TABLE>\n");
1790
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1791
            for(i=0;i<stream->nb_streams;i++) {
1792
                AVStream *st = stream->streams[i];
1793
                FeedData *fdata = st->priv_data;
1794
                enc = st->codec;
1795

1796
                avcodec_string(buf, sizeof(buf), enc);
1797
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1798
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1799
                    avg /= enc->frame_size;
1800
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1801
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1802
            }
1803
            url_fprintf(pb, "</TABLE>\n");
1804
            stream = stream->next_feed;
1805
        }
1806
    }
1807
#endif
1808

    
1809
    /* connection status */
1810
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1811

    
1812
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1813
                 nb_connections, nb_max_connections);
1814

    
1815
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1816
                 current_bandwidth, max_bandwidth);
1817

    
1818
    url_fprintf(pb, "<TABLE>\n");
1819
    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");
1820
    c1 = first_http_ctx;
1821
    i = 0;
1822
    while (c1 != NULL) {
1823
        int bitrate;
1824
        int j;
1825

    
1826
        bitrate = 0;
1827
        if (c1->stream) {
1828
            for (j = 0; j < c1->stream->nb_streams; j++) {
1829
                if (!c1->stream->feed) {
1830
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1831
                } else {
1832
                    if (c1->feed_streams[j] >= 0) {
1833
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1834
                    }
1835
                }
1836
            }
1837
        }
1838

    
1839
        i++;
1840
        p = inet_ntoa(c1->from_addr.sin_addr);
1841
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1842
                    i,
1843
                    c1->stream ? c1->stream->filename : "",
1844
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1845
                    p,
1846
                    c1->protocol,
1847
                    http_state[c1->state]);
1848
        fmt_bytecount(pb, bitrate);
1849
        url_fprintf(pb, "<td align=right>");
1850
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1851
        url_fprintf(pb, "<td align=right>");
1852
        fmt_bytecount(pb, c1->data_count);
1853
        url_fprintf(pb, "\n");
1854
        c1 = c1->next;
1855
    }
1856
    url_fprintf(pb, "</TABLE>\n");
1857

    
1858
    /* date */
1859
    ti = time(NULL);
1860
    p = ctime(&ti);
1861
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1862
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1863

    
1864
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1865
    c->buffer_ptr = c->pb_buffer;
1866
    c->buffer_end = c->pb_buffer + len;
1867
}
1868

    
1869
/* check if the parser needs to be opened for stream i */
1870
static void open_parser(AVFormatContext *s, int i)
1871
{
1872
    AVStream *st = s->streams[i];
1873
    AVCodec *codec;
1874

    
1875
    if (!st->codec->codec) {
1876
        codec = avcodec_find_decoder(st->codec->codec_id);
1877
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1878
            st->codec->parse_only = 1;
1879
            if (avcodec_open(st->codec, codec) < 0) {
1880
                st->codec->parse_only = 0;
1881
            }
1882
        }
1883
    }
1884
}
1885

    
1886
static int open_input_stream(HTTPContext *c, const char *info)
1887
{
1888
    char buf[128];
1889
    char input_filename[1024];
1890
    AVFormatContext *s;
1891
    int buf_size, i;
1892
    int64_t stream_pos;
1893

    
1894
    /* find file name */
1895
    if (c->stream->feed) {
1896
        strcpy(input_filename, c->stream->feed->feed_filename);
1897
        buf_size = FFM_PACKET_SIZE;
1898
        /* compute position (absolute time) */
1899
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1900
            stream_pos = parse_date(buf, 0);
1901
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1902
            int prebuffer = strtol(buf, 0, 10);
1903
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1904
        } else {
1905
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1906
        }
1907
    } else {
1908
        strcpy(input_filename, c->stream->feed_filename);
1909
        buf_size = 0;
1910
        /* compute position (relative time) */
1911
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1912
            stream_pos = parse_date(buf, 1);
1913
        } else {
1914
            stream_pos = 0;
1915
        }
1916
    }
1917
    if (input_filename[0] == '\0')
1918
        return -1;
1919

    
1920
#if 0
1921
    { time_t when = stream_pos / 1000000;
1922
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1923
    }
1924
#endif
1925

    
1926
    /* open stream */
1927
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1928
                           buf_size, c->stream->ap_in) < 0) {
1929
        http_log("%s not found", input_filename);
1930
        return -1;
1931
    }
1932
    c->fmt_in = s;
1933

    
1934
    /* open each parser */
1935
    for(i=0;i<s->nb_streams;i++)
1936
        open_parser(s, i);
1937

    
1938
    /* choose stream as clock source (we favorize video stream if
1939
       present) for packet sending */
1940
    c->pts_stream_index = 0;
1941
    for(i=0;i<c->stream->nb_streams;i++) {
1942
        if (c->pts_stream_index == 0 &&
1943
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1944
            c->pts_stream_index = i;
1945
        }
1946
    }
1947

    
1948
#if 1
1949
    if (c->fmt_in->iformat->read_seek) {
1950
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1951
    }
1952
#endif
1953
    /* set the start time (needed for maxtime and RTP packet timing) */
1954
    c->start_time = cur_time;
1955
    c->first_pts = AV_NOPTS_VALUE;
1956
    return 0;
1957
}
1958

    
1959
/* return the server clock (in us) */
1960
static int64_t get_server_clock(HTTPContext *c)
1961
{
1962
    /* compute current pts value from system time */
1963
    return (int64_t)(cur_time - c->start_time) * 1000LL;
1964
}
1965

    
1966
/* return the estimated time at which the current packet must be sent
1967
   (in us) */
1968
static int64_t get_packet_send_clock(HTTPContext *c)
1969
{
1970
    int bytes_left, bytes_sent, frame_bytes;
1971

    
1972
    frame_bytes = c->cur_frame_bytes;
1973
    if (frame_bytes <= 0) {
1974
        return c->cur_pts;
1975
    } else {
1976
        bytes_left = c->buffer_end - c->buffer_ptr;
1977
        bytes_sent = frame_bytes - bytes_left;
1978
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1979
    }
1980
}
1981

    
1982

    
1983
static int http_prepare_data(HTTPContext *c)
1984
{
1985
    int i, len, ret;
1986
    AVFormatContext *ctx;
1987

    
1988
    av_freep(&c->pb_buffer);
1989
    switch(c->state) {
1990
    case HTTPSTATE_SEND_DATA_HEADER:
1991
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1992
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
1993
                c->stream->author);
1994
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
1995
                c->stream->comment);
1996
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
1997
                c->stream->copyright);
1998
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
1999
                c->stream->title);
2000

    
2001
        /* open output stream by using specified codecs */
2002
        c->fmt_ctx.oformat = c->stream->fmt;
2003
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2004
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2005
            AVStream *st;
2006
            AVStream *src;
2007
            st = av_mallocz(sizeof(AVStream));
2008
            st->codec= avcodec_alloc_context();
2009
            c->fmt_ctx.streams[i] = st;
2010
            /* if file or feed, then just take streams from FFStream struct */
2011
            if (!c->stream->feed ||
2012
                c->stream->feed == c->stream)
2013
                src = c->stream->streams[i];
2014
            else
2015
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2016

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

    
2028
        /* prepare header and save header data in a stream */
2029
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2030
            /* XXX: potential leak */
2031
            return -1;
2032
        }
2033
        c->fmt_ctx.pb.is_streamed = 1;
2034

    
2035
        av_set_parameters(&c->fmt_ctx, NULL);
2036
        av_write_header(&c->fmt_ctx);
2037

    
2038
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2039
        c->buffer_ptr = c->pb_buffer;
2040
        c->buffer_end = c->pb_buffer + len;
2041

    
2042
        c->state = HTTPSTATE_SEND_DATA;
2043
        c->last_packet_sent = 0;
2044
        break;
2045
    case HTTPSTATE_SEND_DATA:
2046
        /* find a new packet */
2047
        {
2048
            AVPacket pkt;
2049

    
2050
            /* read a packet from the input stream */
2051
            if (c->stream->feed) {
2052
                ffm_set_write_index(c->fmt_in,
2053
                                    c->stream->feed->feed_write_index,
2054
                                    c->stream->feed->feed_size);
2055
            }
2056

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

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

    
2162
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2163
                        if (c->is_packetized) {
2164
                            int max_packet_size;
2165
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2166
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2167
                            else
2168
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2169
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2170
                        } else {
2171
                            ret = url_open_dyn_buf(&ctx->pb);
2172
                        }
2173
                        if (ret < 0) {
2174
                            /* XXX: potential leak */
2175
                            return -1;
2176
                        }
2177
                        if (av_write_frame(ctx, &pkt)) {
2178
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2179
                        }
2180

    
2181
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2182
                        c->cur_frame_bytes = len;
2183
                        c->buffer_ptr = c->pb_buffer;
2184
                        c->buffer_end = c->pb_buffer + len;
2185

    
2186
                        codec->frame_number++;
2187
                        if (len == 0)
2188
                            goto redo;
2189
                    }
2190
                    av_free_packet(&pkt);
2191
                }
2192
            }
2193
        }
2194
        break;
2195
    default:
2196
    case HTTPSTATE_SEND_DATA_TRAILER:
2197
        /* last packet test ? */
2198
        if (c->last_packet_sent || c->is_packetized)
2199
            return -1;
2200
        ctx = &c->fmt_ctx;
2201
        /* prepare header */
2202
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2203
            /* XXX: potential leak */
2204
            return -1;
2205
        }
2206
        av_write_trailer(ctx);
2207
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2208
        c->buffer_ptr = c->pb_buffer;
2209
        c->buffer_end = c->pb_buffer + len;
2210

    
2211
        c->last_packet_sent = 1;
2212
        break;
2213
    }
2214
    return 0;
2215
}
2216

    
2217
/* in bit/s */
2218
#define SHORT_TERM_BANDWIDTH 8000000
2219

    
2220
/* should convert the format at the same time */
2221
/* send data starting at c->buffer_ptr to the output connection
2222
   (either UDP or TCP connection) */
2223
static int http_send_data(HTTPContext *c)
2224
{
2225
    int len, ret;
2226

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

    
2257
                c->data_count += len;
2258
                update_datarate(&c->datarate, c->data_count);
2259
                if (c->stream)
2260
                    c->stream->bytes_served += len;
2261

    
2262
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2263
                    /* RTP packets are sent inside the RTSP TCP connection */
2264
                    ByteIOContext pb1, *pb = &pb1;
2265
                    int interleaved_index, size;
2266
                    uint8_t header[4];
2267
                    HTTPContext *rtsp_c;
2268

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

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

    
2346
static int http_start_receive_data(HTTPContext *c)
2347
{
2348
    int fd;
2349

    
2350
    if (c->stream->feed_opened)
2351
        return -1;
2352

    
2353
    /* Don't permit writing to this one */
2354
    if (c->stream->readonly)
2355
        return -1;
2356

    
2357
    /* open feed */
2358
    fd = open(c->stream->feed_filename, O_RDWR);
2359
    if (fd < 0)
2360
        return -1;
2361
    c->feed_fd = fd;
2362

    
2363
    c->stream->feed_write_index = ffm_read_write_index(fd);
2364
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2365
    lseek(fd, 0, SEEK_SET);
2366

    
2367
    /* init buffer input */
2368
    c->buffer_ptr = c->buffer;
2369
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2370
    c->stream->feed_opened = 1;
2371
    return 0;
2372
}
2373

    
2374
static int http_receive_data(HTTPContext *c)
2375
{
2376
    HTTPContext *c1;
2377

    
2378
    if (c->buffer_end > c->buffer_ptr) {
2379
        int len;
2380

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

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

    
2405
    if (c->buffer_ptr >= c->buffer_end) {
2406
        FFStream *feed = c->stream;
2407
        /* a packet has been received : write it in the store, except
2408
           if header */
2409
        if (c->data_count > FFM_PACKET_SIZE) {
2410

    
2411
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2412
            /* XXX: use llseek or url_seek */
2413
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2414
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2415

    
2416
            feed->feed_write_index += FFM_PACKET_SIZE;
2417
            /* update file size */
2418
            if (feed->feed_write_index > c->stream->feed_size)
2419
                feed->feed_size = feed->feed_write_index;
2420

    
2421
            /* handle wrap around if max file size reached */
2422
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2423
                feed->feed_write_index = FFM_PACKET_SIZE;
2424

    
2425
            /* write index */
2426
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2427

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

    
2442
            memset(&s, 0, sizeof(s));
2443

    
2444
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2445
            pb->buf_end = c->buffer_end;        /* ?? */
2446
            pb->is_streamed = 1;
2447

    
2448
            /* use feed output format name to find corresponding input format */
2449
            fmt_in = av_find_input_format(feed->fmt->name);
2450
            if (!fmt_in)
2451
                goto fail;
2452

    
2453
            if (fmt_in->priv_data_size > 0) {
2454
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2455
                if (!s.priv_data)
2456
                    goto fail;
2457
            } else
2458
                s.priv_data = NULL;
2459

    
2460
            if (fmt_in->read_header(&s, 0) < 0) {
2461
                av_freep(&s.priv_data);
2462
                goto fail;
2463
            }
2464

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

    
2479
    return 0;
2480
 fail:
2481
    c->stream->feed_opened = 0;
2482
    close(c->feed_fd);
2483
    return -1;
2484
}
2485

    
2486
/********************************************************************/
2487
/* RTSP handling */
2488

    
2489
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2490
{
2491
    const char *str;
2492
    time_t ti;
2493
    char *p;
2494
    char buf2[32];
2495

    
2496
    switch(error_number) {
2497
#define DEF(n, c, s) case c: str = s; break;
2498
#include "rtspcodes.h"
2499
#undef DEF
2500
    default:
2501
        str = "Unknown Error";
2502
        break;
2503
    }
2504

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

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

    
2518
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2519
{
2520
    rtsp_reply_header(c, error_number);
2521
    url_fprintf(c->pb, "\r\n");
2522
}
2523

    
2524
static int rtsp_parse_request(HTTPContext *c)
2525
{
2526
    const char *p, *p1, *p2;
2527
    char cmd[32];
2528
    char url[1024];
2529
    char protocol[32];
2530
    char line[1024];
2531
    ByteIOContext pb1;
2532
    int len;
2533
    RTSPHeader header1, *header = &header1;
2534

    
2535
    c->buffer_ptr[0] = '\0';
2536
    p = c->buffer;
2537

    
2538
    get_word(cmd, sizeof(cmd), &p);
2539
    get_word(url, sizeof(url), &p);
2540
    get_word(protocol, sizeof(protocol), &p);
2541

    
2542
    pstrcpy(c->method, sizeof(c->method), cmd);
2543
    pstrcpy(c->url, sizeof(c->url), url);
2544
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2545

    
2546
    c->pb = &pb1;
2547
    if (url_open_dyn_buf(c->pb) < 0) {
2548
        /* XXX: cannot do more */
2549
        c->pb = NULL; /* safety */
2550
        return -1;
2551
    }
2552

    
2553
    /* check version name */
2554
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2555
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2556
        goto the_end;
2557
    }
2558

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

    
2585
    /* handle sequence number */
2586
    c->seq = header->seq;
2587

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

    
2616
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2617
   AVFormatContext */
2618
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2619
                                   struct in_addr my_ip)
2620
{
2621
    ByteIOContext pb1, *pb = &pb1;
2622
    int i, payload_type, port, private_payload_type, j;
2623
    const char *ipstr, *title, *mediatype;
2624
    AVStream *st;
2625

    
2626
    if (url_open_dyn_buf(pb) < 0)
2627
        return -1;
2628

    
2629
    /* general media info */
2630

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

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

    
2716
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2717
{
2718
    FFStream *stream;
2719
    char path1[1024];
2720
    const char *path;
2721
    uint8_t *content;
2722
    int content_length, len;
2723
    struct sockaddr_in my_addr;
2724

    
2725
    /* find which url is asked */
2726
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2727
    path = path1;
2728
    if (*path == '/')
2729
        path++;
2730

    
2731
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2732
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2733
            !strcmp(path, stream->filename)) {
2734
            goto found;
2735
        }
2736
    }
2737
    /* no stream found */
2738
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2739
    return;
2740

    
2741
 found:
2742
    /* prepare the media description in sdp format */
2743

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

    
2759
static HTTPContext *find_rtp_session(const char *session_id)
2760
{
2761
    HTTPContext *c;
2762

    
2763
    if (session_id[0] == '\0')
2764
        return NULL;
2765

    
2766
    for(c = first_http_ctx; c != NULL; c = c->next) {
2767
        if (!strcmp(c->session_id, session_id))
2768
            return c;
2769
    }
2770
    return NULL;
2771
}
2772

    
2773
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2774
{
2775
    RTSPTransportField *th;
2776
    int i;
2777

    
2778
    for(i=0;i<h->nb_transports;i++) {
2779
        th = &h->transports[i];
2780
        if (th->protocol == protocol)
2781
            return th;
2782
    }
2783
    return NULL;
2784
}
2785

    
2786
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2787
                           RTSPHeader *h)
2788
{
2789
    FFStream *stream;
2790
    int stream_index, port;
2791
    char buf[1024];
2792
    char path1[1024];
2793
    const char *path;
2794
    HTTPContext *rtp_c;
2795
    RTSPTransportField *th;
2796
    struct sockaddr_in dest_addr;
2797
    RTSPActionServerSetup setup;
2798

    
2799
    /* find which url is asked */
2800
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2801
    path = path1;
2802
    if (*path == '/')
2803
        path++;
2804

    
2805
    /* now check each stream */
2806
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2807
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2808
            /* accept aggregate filenames only if single stream */
2809
            if (!strcmp(path, stream->filename)) {
2810
                if (stream->nb_streams != 1) {
2811
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2812
                    return;
2813
                }
2814
                stream_index = 0;
2815
                goto found;
2816
            }
2817

    
2818
            for(stream_index = 0; stream_index < stream->nb_streams;
2819
                stream_index++) {
2820
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2821
                         stream->filename, stream_index);
2822
                if (!strcmp(path, buf))
2823
                    goto found;
2824
            }
2825
        }
2826
    }
2827
    /* no stream found */
2828
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2829
    return;
2830
 found:
2831

    
2832
    /* generate session id if needed */
2833
    if (h->session_id[0] == '\0') {
2834
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2835
                 av_random(&random_state), av_random(&random_state));
2836
    }
2837

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

    
2851
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2852
                                   th->protocol);
2853
        if (!rtp_c) {
2854
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2855
            return;
2856
        }
2857

    
2858
        /* open input stream */
2859
        if (open_input_stream(rtp_c, "") < 0) {
2860
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2861
            return;
2862
        }
2863
    }
2864

    
2865
    /* test if stream is OK (test needed because several SETUP needs
2866
       to be done for a given file) */
2867
    if (rtp_c->stream != stream) {
2868
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2869
        return;
2870
    }
2871

    
2872
    /* test if stream is already set up */
2873
    if (rtp_c->rtp_ctx[stream_index]) {
2874
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2875
        return;
2876
    }
2877

    
2878
    /* check transport */
2879
    th = find_transport(h, rtp_c->rtp_protocol);
2880
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2881
                th->client_port_min <= 0)) {
2882
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2883
        return;
2884
    }
2885

    
2886
    /* setup default options */
2887
    setup.transport_option[0] = '\0';
2888
    dest_addr = rtp_c->from_addr;
2889
    dest_addr.sin_port = htons(th->client_port_min);
2890

    
2891
    /* add transport option if needed */
2892
    if (ff_rtsp_callback) {
2893
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2894
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2895
                             (char *)&setup, sizeof(setup),
2896
                             stream->rtsp_option) < 0) {
2897
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2898
            return;
2899
        }
2900
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2901
    }
2902

    
2903
    /* setup stream */
2904
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2905
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2906
        return;
2907
    }
2908

    
2909
    /* now everything is OK, so we can send the connection parameters */
2910
    rtsp_reply_header(c, RTSP_STATUS_OK);
2911
    /* session ID */
2912
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2913

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

    
2934

    
2935
    url_fprintf(c->pb, "\r\n");
2936
}
2937

    
2938

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

    
2950
    rtp_c = find_rtp_session(session_id);
2951
    if (!rtp_c)
2952
        return NULL;
2953

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

    
2971
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2972
{
2973
    HTTPContext *rtp_c;
2974

    
2975
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2976
    if (!rtp_c) {
2977
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2978
        return;
2979
    }
2980

    
2981
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2982
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2983
        rtp_c->state != HTTPSTATE_READY) {
2984
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2985
        return;
2986
    }
2987

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

    
2996
    rtp_c->state = HTTPSTATE_SEND_DATA;
2997

    
2998
    /* now everything is OK, so we can send the connection parameters */
2999
    rtsp_reply_header(c, RTSP_STATUS_OK);
3000
    /* session ID */
3001
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3002
    url_fprintf(c->pb, "\r\n");
3003
}
3004

    
3005
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3006
{
3007
    HTTPContext *rtp_c;
3008

    
3009
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3010
    if (!rtp_c) {
3011
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3012
        return;
3013
    }
3014

    
3015
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3016
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3017
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3018
        return;
3019
    }
3020

    
3021
    rtp_c->state = HTTPSTATE_READY;
3022
    rtp_c->first_pts = AV_NOPTS_VALUE;
3023
    /* now everything is OK, so we can send the connection parameters */
3024
    rtsp_reply_header(c, RTSP_STATUS_OK);
3025
    /* session ID */
3026
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3027
    url_fprintf(c->pb, "\r\n");
3028
}
3029

    
3030
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3031
{
3032
    HTTPContext *rtp_c;
3033

    
3034
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3035
    if (!rtp_c) {
3036
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3037
        return;
3038
    }
3039

    
3040
    /* abort the session */
3041
    close_connection(rtp_c);
3042

    
3043
    if (ff_rtsp_callback) {
3044
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3045
                         NULL, 0,
3046
                         rtp_c->stream->rtsp_option);
3047
    }
3048

    
3049
    /* now everything is OK, so we can send the connection parameters */
3050
    rtsp_reply_header(c, RTSP_STATUS_OK);
3051
    /* session ID */
3052
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3053
    url_fprintf(c->pb, "\r\n");
3054
}
3055

    
3056

    
3057
/********************************************************************/
3058
/* RTP handling */
3059

    
3060
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3061
                                       FFStream *stream, const char *session_id,
3062
                                       enum RTSPProtocol rtp_protocol)
3063
{
3064
    HTTPContext *c = NULL;
3065
    const char *proto_str;
3066

    
3067
    /* XXX: should output a warning page when coming
3068
       close to the connection limit */
3069
    if (nb_connections >= nb_max_connections)
3070
        goto fail;
3071

    
3072
    /* add a new connection */
3073
    c = av_mallocz(sizeof(HTTPContext));
3074
    if (!c)
3075
        goto fail;
3076

    
3077
    c->fd = -1;
3078
    c->poll_entry = NULL;
3079
    c->from_addr = *from_addr;
3080
    c->buffer_size = IOBUFFER_INIT_SIZE;
3081
    c->buffer = av_malloc(c->buffer_size);
3082
    if (!c->buffer)
3083
        goto fail;
3084
    nb_connections++;
3085
    c->stream = stream;
3086
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3087
    c->state = HTTPSTATE_READY;
3088
    c->is_packetized = 1;
3089
    c->rtp_protocol = rtp_protocol;
3090

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

    
3109
    current_bandwidth += stream->bandwidth;
3110

    
3111
    c->next = first_http_ctx;
3112
    first_http_ctx = c;
3113
    return c;
3114

    
3115
 fail:
3116
    if (c) {
3117
        av_free(c->buffer);
3118
        av_free(c);
3119
    }
3120
    return NULL;
3121
}
3122

    
3123
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3124
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3125
   used. */
3126
static int rtp_new_av_stream(HTTPContext *c,
3127
                             int stream_index, struct sockaddr_in *dest_addr,
3128
                             HTTPContext *rtsp_c)
3129
{
3130
    AVFormatContext *ctx;
3131
    AVStream *st;
3132
    char *ipaddr;
3133
    URLContext *h;
3134
    uint8_t *dummy_buf;
3135
    char buf2[32];
3136
    int max_packet_size;
3137

    
3138
    /* now we can open the relevant output stream */
3139
    ctx = av_alloc_format_context();
3140
    if (!ctx)
3141
        return -1;
3142
    ctx->oformat = &rtp_muxer;
3143

    
3144
    st = av_mallocz(sizeof(AVStream));
3145
    if (!st)
3146
        goto fail;
3147
    st->codec= avcodec_alloc_context();
3148
    ctx->nb_streams = 1;
3149
    ctx->streams[0] = st;
3150

    
3151
    if (!c->stream->feed ||
3152
        c->stream->feed == c->stream) {
3153
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3154
    } else {
3155
        memcpy(st,
3156
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3157
               sizeof(AVStream));
3158
    }
3159

    
3160
    /* build destination RTP address */
3161
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3162

    
3163
    switch(c->rtp_protocol) {
3164
    case RTSP_PROTOCOL_RTP_UDP:
3165
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3166
        /* RTP/UDP case */
3167

    
3168
        /* XXX: also pass as parameter to function ? */
3169
        if (c->stream->is_multicast) {
3170
            int ttl;
3171
            ttl = c->stream->multicast_ttl;
3172
            if (!ttl)
3173
                ttl = 16;
3174
            snprintf(ctx->filename, sizeof(ctx->filename),
3175
                     "rtp://%s:%d?multicast=1&ttl=%d",
3176
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3177
        } else {
3178
            snprintf(ctx->filename, sizeof(ctx->filename),
3179
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3180
        }
3181

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

    
3196
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3197
             ipaddr, ntohs(dest_addr->sin_port),
3198
             ctime1(buf2),
3199
             c->stream->filename, stream_index, c->protocol);
3200

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

    
3217
    c->rtp_ctx[stream_index] = ctx;
3218
    return 0;
3219
}
3220

    
3221
/********************************************************************/
3222
/* ffserver initialization */
3223

    
3224
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3225
{
3226
    AVStream *fst;
3227

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

    
3241
/* return the stream number in the feed */
3242
static int add_av_stream(FFStream *feed, AVStream *st)
3243
{
3244
    AVStream *fst;
3245
    AVCodecContext *av, *av1;
3246
    int i;
3247

    
3248
    av = st->codec;
3249
    for(i=0;i<feed->nb_streams;i++) {
3250
        st = feed->streams[i];
3251
        av1 = st->codec;
3252
        if (av1->codec_id == av->codec_id &&
3253
            av1->codec_type == av->codec_type &&
3254
            av1->bit_rate == av->bit_rate) {
3255

    
3256
            switch(av->codec_type) {
3257
            case CODEC_TYPE_AUDIO:
3258
                if (av1->channels == av->channels &&
3259
                    av1->sample_rate == av->sample_rate)
3260
                    goto found;
3261
                break;
3262
            case CODEC_TYPE_VIDEO:
3263
                if (av1->width == av->width &&
3264
                    av1->height == av->height &&
3265
                    av1->time_base.den == av->time_base.den &&
3266
                    av1->time_base.num == av->time_base.num &&
3267
                    av1->gop_size == av->gop_size)
3268
                    goto found;
3269
                break;
3270
            default:
3271
                av_abort();
3272
            }
3273
        }
3274
    }
3275

    
3276
    fst = add_av_stream1(feed, av);
3277
    if (!fst)
3278
        return -1;
3279
    return feed->nb_streams - 1;
3280
 found:
3281
    return i;
3282
}
3283

    
3284
static void remove_stream(FFStream *stream)
3285
{
3286
    FFStream **ps;
3287
    ps = &first_stream;
3288
    while (*ps != NULL) {
3289
        if (*ps == stream) {
3290
            *ps = (*ps)->next;
3291
        } else {
3292
            ps = &(*ps)->next;
3293
        }
3294
    }
3295
}
3296

    
3297
/* specific mpeg4 handling : we extract the raw parameters */
3298
static void extract_mpeg4_header(AVFormatContext *infile)
3299
{
3300
    int mpeg4_count, i, size;
3301
    AVPacket pkt;
3302
    AVStream *st;
3303
    const uint8_t *p;
3304

    
3305
    mpeg4_count = 0;
3306
    for(i=0;i<infile->nb_streams;i++) {
3307
        st = infile->streams[i];
3308
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3309
            st->codec->extradata_size == 0) {
3310
            mpeg4_count++;
3311
        }
3312
    }
3313
    if (!mpeg4_count)
3314
        return;
3315

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

    
3346
/* compute the needed AVStream for each file */
3347
static void build_file_streams(void)
3348
{
3349
    FFStream *stream, *stream_next;
3350
    AVFormatContext *infile;
3351
    int i;
3352

    
3353
    /* gather all streams */
3354
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3355
        stream_next = stream->next;
3356
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3357
            !stream->feed) {
3358
            /* the stream comes from a file */
3359
            /* try to open the file */
3360
            /* open stream */
3361
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3362
            if (stream->fmt == &rtp_muxer) {
3363
                /* specific case : if transport stream output to RTP,
3364
                   we use a raw transport stream reader */
3365
                stream->ap_in->mpeg2ts_raw = 1;
3366
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3367
            }
3368

    
3369
            if (av_open_input_file(&infile, stream->feed_filename,
3370
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3371
                http_log("%s not found", stream->feed_filename);
3372
                /* remove stream (no need to spend more time on it) */
3373
            fail:
3374
                remove_stream(stream);
3375
            } else {
3376
                /* find all the AVStreams inside and reference them in
3377
                   'stream' */
3378
                if (av_find_stream_info(infile) < 0) {
3379
                    http_log("Could not find codec parameters from '%s'",
3380
                             stream->feed_filename);
3381
                    av_close_input_file(infile);
3382
                    goto fail;
3383
                }
3384
                extract_mpeg4_header(infile);
3385

    
3386
                for(i=0;i<infile->nb_streams;i++) {
3387
                    add_av_stream1(stream, infile->streams[i]->codec);
3388
                }
3389
                av_close_input_file(infile);
3390
            }
3391
        }
3392
    }
3393
}
3394

    
3395
/* compute the needed AVStream for each feed */
3396
static void build_feed_streams(void)
3397
{
3398
    FFStream *stream, *feed;
3399
    int i;
3400

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

    
3414
    /* gather all streams */
3415
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3416
        feed = stream->feed;
3417
        if (feed) {
3418
            if (stream->is_feed) {
3419
                for(i=0;i<stream->nb_streams;i++) {
3420
                    stream->feed_streams[i] = i;
3421
                }
3422
            }
3423
        }
3424
    }
3425

    
3426
    /* create feed files if needed */
3427
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3428
        int fd;
3429

    
3430
        if (url_exist(feed->feed_filename)) {
3431
            /* See if it matches */
3432
            AVFormatContext *s;
3433
            int matches = 0;
3434

    
3435
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3436
                /* Now see if it matches */
3437
                if (s->nb_streams == feed->nb_streams) {
3438
                    matches = 1;
3439
                    for(i=0;i<s->nb_streams;i++) {
3440
                        AVStream *sf, *ss;
3441
                        sf = feed->streams[i];
3442
                        ss = s->streams[i];
3443

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

    
3452
                            ccf = sf->codec;
3453
                            ccs = ss->codec;
3454
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3455

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

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

    
3508
            if (feed->readonly) {
3509
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3510
                    feed->feed_filename);
3511
                exit(1);
3512
            }
3513

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

    
3541
        feed->feed_write_index = ffm_read_write_index(fd);
3542
        feed->feed_size = lseek(fd, 0, SEEK_END);
3543
        /* ensure that we do not wrap before the end of file */
3544
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3545
            feed->feed_max_size = feed->feed_size;
3546

    
3547
        close(fd);
3548
    }
3549
}
3550

    
3551
/* compute the bandwidth used by each stream */
3552
static void compute_bandwidth(void)
3553
{
3554
    int bandwidth, i;
3555
    FFStream *stream;
3556

    
3557
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3558
        bandwidth = 0;
3559
        for(i=0;i<stream->nb_streams;i++) {
3560
            AVStream *st = stream->streams[i];
3561
            switch(st->codec->codec_type) {
3562
            case CODEC_TYPE_AUDIO:
3563
            case CODEC_TYPE_VIDEO:
3564
                bandwidth += st->codec->bit_rate;
3565
                break;
3566
            default:
3567
                break;
3568
            }
3569
        }
3570
        stream->bandwidth = (bandwidth + 999) / 1000;
3571
    }
3572
}
3573

    
3574
static void get_arg(char *buf, int buf_size, const char **pp)
3575
{
3576
    const char *p;
3577
    char *q;
3578
    int quote;
3579

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

    
3606
/* add a codec and set the default parameters */
3607
static void add_codec(FFStream *stream, AVCodecContext *av)
3608
{
3609
    AVStream *st;
3610

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

    
3644
        if (!av->nsse_weight)
3645
            av->nsse_weight = 8;
3646

    
3647
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3648
        av->me_method = ME_EPZS;
3649
        av->rc_buffer_aggressivity = 1.0;
3650

    
3651
        if (!av->rc_eq)
3652
            av->rc_eq = "tex^qComp";
3653
        if (!av->i_quant_factor)
3654
            av->i_quant_factor = -0.8;
3655
        if (!av->b_quant_factor)
3656
            av->b_quant_factor = 1.25;
3657
        if (!av->b_quant_offset)
3658
            av->b_quant_offset = 1.25;
3659
        if (!av->rc_max_rate)
3660
            av->rc_max_rate = av->bit_rate * 2;
3661

    
3662
        if (av->rc_max_rate && !av->rc_buffer_size) {
3663
            av->rc_buffer_size = av->rc_max_rate;
3664
        }
3665

    
3666

    
3667
        break;
3668
    default:
3669
        av_abort();
3670
    }
3671

    
3672
    st = av_mallocz(sizeof(AVStream));
3673
    if (!st)
3674
        return;
3675
    st->codec = avcodec_alloc_context();
3676
    stream->streams[stream->nb_streams++] = st;
3677
    memcpy(st->codec, av, sizeof(AVCodecContext));
3678
}
3679

    
3680
static int opt_audio_codec(const char *arg)
3681
{
3682
    AVCodec *p;
3683

    
3684
    p = first_avcodec;
3685
    while (p) {
3686
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3687
            break;
3688
        p = p->next;
3689
    }
3690
    if (p == NULL) {
3691
        return CODEC_ID_NONE;
3692
    }
3693

    
3694
    return p->id;
3695
}
3696

    
3697
static int opt_video_codec(const char *arg)
3698
{
3699
    AVCodec *p;
3700

    
3701
    p = first_avcodec;
3702
    while (p) {
3703
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3704
            break;
3705
        p = p->next;
3706
    }
3707
    if (p == NULL) {
3708
        return CODEC_ID_NONE;
3709
    }
3710

    
3711
    return p->id;
3712
}
3713

    
3714
/* simplistic plugin support */
3715

    
3716
#ifdef HAVE_DLOPEN
3717
static void load_module(const char *filename)
3718
{
3719
    void *dll;
3720
    void (*init_func)(void);
3721
    dll = dlopen(filename, RTLD_NOW);
3722
    if (!dll) {
3723
        fprintf(stderr, "Could not load module '%s' - %s\n",
3724
                filename, dlerror());
3725
        return;
3726
    }
3727

    
3728
    init_func = dlsym(dll, "ffserver_module_init");
3729
    if (!init_func) {
3730
        fprintf(stderr,
3731
                "%s: init function 'ffserver_module_init()' not found\n",
3732
                filename);
3733
        dlclose(dll);
3734
    }
3735

    
3736
    init_func();
3737
}
3738
#endif
3739

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

    
3753
    f = fopen(filename, "r");
3754
    if (!f) {
3755
        perror(filename);
3756
        return -1;
3757
    }
3758

    
3759
    errors = 0;
3760
    line_num = 0;
3761
    first_stream = NULL;
3762
    last_stream = &first_stream;
3763
    first_feed = NULL;
3764
    last_feed = &first_feed;
3765
    stream = NULL;
3766
    feed = NULL;
3767
    redirect = NULL;
3768
    audio_id = CODEC_ID_NONE;
3769
    video_id = CODEC_ID_NONE;
3770
    for(;;) {
3771
        if (fgets(line, sizeof(line), f) == NULL)
3772
            break;
3773
        line_num++;
3774
        p = line;
3775
        while (isspace(*p))
3776
            p++;
3777
        if (*p == '\0' || *p == '#')
3778
            continue;
3779

    
3780
        get_arg(cmd, sizeof(cmd), &p);
3781

    
3782
        if (!strcasecmp(cmd, "Port")) {
3783
            get_arg(arg, sizeof(arg), &p);
3784
            my_http_addr.sin_port = htons (atoi(arg));
3785
        } else if (!strcasecmp(cmd, "BindAddress")) {
3786
            get_arg(arg, sizeof(arg), &p);
3787
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3788
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3789
                        filename, line_num, arg);
3790
                errors++;
3791
            }
3792
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3793
            ffserver_daemon = 0;
3794
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3795
            get_arg(arg, sizeof(arg), &p);
3796
            my_rtsp_addr.sin_port = htons (atoi(arg));
3797
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3798
            get_arg(arg, sizeof(arg), &p);
3799
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3800
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3801
                        filename, line_num, arg);
3802
                errors++;
3803
            }
3804
        } else if (!strcasecmp(cmd, "MaxClients")) {
3805
            get_arg(arg, sizeof(arg), &p);
3806
            val = atoi(arg);
3807
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3808
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3809
                        filename, line_num, arg);
3810
                errors++;
3811
            } else {
3812
                nb_max_connections = val;
3813
            }
3814
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3815
            get_arg(arg, sizeof(arg), &p);
3816
            val = atoi(arg);
3817
            if (val < 10 || val > 100000) {
3818
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3819
                        filename, line_num, arg);
3820
                errors++;
3821
            } else {
3822
                max_bandwidth = val;
3823
            }
3824
        } else if (!strcasecmp(cmd, "CustomLog")) {
3825
            get_arg(logfilename, sizeof(logfilename), &p);
3826
        } else if (!strcasecmp(cmd, "<Feed")) {
3827
            /*********************************************/
3828
            /* Feed related options */
3829
            char *q;
3830
            if (stream || feed) {
3831
                fprintf(stderr, "%s:%d: Already in a tag\n",
3832
                        filename, line_num);
3833
            } else {
3834
                feed = av_mallocz(sizeof(FFStream));
3835
                /* add in stream list */
3836
                *last_stream = feed;
3837
                last_stream = &feed->next;
3838
                /* add in feed list */
3839
                *last_feed = feed;
3840
                last_feed = &feed->next_feed;
3841

    
3842
                get_arg(feed->filename, sizeof(feed->filename), &p);
3843
                q = strrchr(feed->filename, '>');
3844
                if (*q)
3845
                    *q = '\0';
3846
                feed->fmt = guess_format("ffm", NULL, NULL);
3847
                /* defaut feed file */
3848
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3849
                         "/tmp/%s.ffm", feed->filename);
3850
                feed->feed_max_size = 5 * 1024 * 1024;
3851
                feed->is_feed = 1;
3852
                feed->feed = feed; /* self feeding :-) */
3853
            }
3854
        } else if (!strcasecmp(cmd, "Launch")) {
3855
            if (feed) {
3856
                int i;
3857

    
3858
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3859

    
3860
                for (i = 0; i < 62; i++) {
3861
                    char argbuf[256];
3862

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

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

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

    
3873
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3874
                    "http://%s:%d/%s",
3875
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3876
                    inet_ntoa(my_http_addr.sin_addr),
3877
                    ntohs(my_http_addr.sin_port), feed->filename);
3878

    
3879
                if (ffserver_debug)
3880
                {
3881
                    int j;
3882
                    fprintf(stdout, "Launch commandline: ");
3883
                    for (j = 0; j <= i; j++)
3884
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3885
                    fprintf(stdout, "\n");
3886
                }
3887
            }
3888
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3889
            if (feed) {
3890
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3891
                feed->readonly = 1;
3892
            } else if (stream) {
3893
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3894
            }
3895
        } else if (!strcasecmp(cmd, "File")) {
3896
            if (feed) {
3897
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3898
            } else if (stream) {
3899
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3900
            }
3901
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3902
            if (feed) {
3903
                const char *p1;
3904
                double fsize;
3905

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

    
3951
                get_arg(stream->filename, sizeof(stream->filename), &p);
3952
                q = strrchr(stream->filename, '>');
3953
                if (*q)
3954
                    *q = '\0';
3955
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3956
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3957
                memset(&video_enc, 0, sizeof(AVCodecContext));
3958
                audio_id = CODEC_ID_NONE;
3959
                video_id = CODEC_ID_NONE;
3960
                if (stream->fmt) {
3961
                    audio_id = stream->fmt->audio_codec;
3962
                    video_id = stream->fmt->video_codec;
3963
                }
3964
            }
3965
        } else if (!strcasecmp(cmd, "Feed")) {
3966
            get_arg(arg, sizeof(arg), &p);
3967
            if (stream) {
3968
                FFStream *sfeed;
3969

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

    
4088
                get_arg(arg, sizeof(arg), &p);
4089

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

    
4240
            get_arg(arg, sizeof(arg), &p);
4241
            if (strcasecmp(arg, "allow") == 0) {
4242
                acl.action = IP_ALLOW;
4243
            } else if (strcasecmp(arg, "deny") == 0) {
4244
                acl.action = IP_DENY;
4245
            } else {
4246
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4247
                        filename, line_num, arg);
4248
                errors++;
4249
            }
4250

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

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

    
4264
            get_arg(arg, sizeof(arg), &p);
4265

    
4266
            if (arg[0]) {
4267
                he = gethostbyname(arg);
4268
                if (!he) {
4269
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4270
                            filename, line_num, arg);
4271
                    errors++;
4272
                } else {
4273
                    /* Only take the first */
4274
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4275
                }
4276
            }
4277

    
4278
            if (!errors) {
4279
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4280
                IPAddressACL **naclp = 0;
4281

    
4282
                *nacl = acl;
4283
                nacl->next = 0;
4284

    
4285
                if (stream) {
4286
                    naclp = &stream->acl;
4287
                } else if (feed) {
4288
                    naclp = &feed->acl;
4289
                } else {
4290
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4291
                            filename, line_num);
4292
                    errors++;
4293
                }
4294

    
4295
                if (naclp) {
4296
                    while (*naclp)
4297
                        naclp = &(*naclp)->next;
4298

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

    
4368
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4369
                q = strrchr(redirect->filename, '>');
4370
                if (*q)
4371
                    *q = '\0';
4372
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4373
            }
4374
        } else if (!strcasecmp(cmd, "URL")) {
4375
            if (redirect) {
4376
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4377
            }
4378
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4379
            if (!redirect) {
4380
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4381
                        filename, line_num);
4382
                errors++;
4383
            }
4384
            if (!redirect->feed_filename[0]) {
4385
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4386
                        filename, line_num);
4387
                errors++;
4388
            }
4389
            redirect = NULL;
4390
        } else if (!strcasecmp(cmd, "LoadModule")) {
4391
            get_arg(arg, sizeof(arg), &p);
4392
#ifdef HAVE_DLOPEN
4393
            load_module(arg);
4394
#else
4395
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4396
                    filename, line_num, arg);
4397
            errors++;
4398
#endif
4399
        } else {
4400
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4401
                    filename, line_num, cmd);
4402
            errors++;
4403
        }
4404
    }
4405

    
4406
    fclose(f);
4407
    if (errors)
4408
        return -1;
4409
    else
4410
        return 0;
4411
}
4412

    
4413

    
4414
#if 0
4415
static void write_packet(FFCodec *ffenc,
4416
                         uint8_t *buf, int size)
4417
{
4418
    PacketHeader hdr;
4419
    AVCodecContext *enc = &ffenc->enc;
4420
    uint8_t *wptr;
4421
    mk_header(&hdr, enc, size);
4422
    wptr = http_fifo.wptr;
4423
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4424
    fifo_write(&http_fifo, buf, size, &wptr);
4425
    /* atomic modification of wptr */
4426
    http_fifo.wptr = wptr;
4427
    ffenc->data_count += size;
4428
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4429
}
4430
#endif
4431

    
4432
static void show_banner(void)
4433
{
4434
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4435
}
4436

    
4437
static void show_help(void)
4438
{
4439
    show_banner();
4440
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4441
           "Hyper fast multi format Audio/Video streaming server\n"
4442
           "\n"
4443
           "-L            : print the LICENSE\n"
4444
           "-h            : this help\n"
4445
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4446
           );
4447
}
4448

    
4449
static void show_license(void)
4450
{
4451
    show_banner();
4452
    printf(
4453
    "FFmpeg is free software; you can redistribute it and/or\n"
4454
    "modify it under the terms of the GNU Lesser General Public\n"
4455
    "License as published by the Free Software Foundation; either\n"
4456
    "version 2.1 of the License, or (at your option) any later version.\n"
4457
    "\n"
4458
    "FFmpeg is distributed in the hope that it will be useful,\n"
4459
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4460
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4461
    "Lesser General Public License for more details.\n"
4462
    "\n"
4463
    "You should have received a copy of the GNU Lesser General Public\n"
4464
    "License along with FFmpeg; if not, write to the Free Software\n"
4465
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4466
    );
4467
}
4468

    
4469
static void handle_child_exit(int sig)
4470
{
4471
    pid_t pid;
4472
    int status;
4473

    
4474
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4475
        FFStream *feed;
4476

    
4477
        for (feed = first_feed; feed; feed = feed->next) {
4478
            if (feed->pid == pid) {
4479
                int uptime = time(0) - feed->pid_start;
4480

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

    
4484
                if (uptime < 30) {
4485
                    /* Turn off any more restarts */
4486
                    feed->child_argv = 0;
4487
                }
4488
            }
4489
        }
4490
    }
4491

    
4492
    need_to_start_children = 1;
4493
}
4494

    
4495
int main(int argc, char **argv)
4496
{
4497
    const char *config_filename;
4498
    int c;
4499
    struct sigaction sigact;
4500

    
4501
    av_register_all();
4502

    
4503
    config_filename = "/etc/ffserver.conf";
4504

    
4505
    my_program_name = argv[0];
4506
    my_program_dir = getcwd(0, 0);
4507
    ffserver_daemon = 1;
4508

    
4509
    for(;;) {
4510
        c = getopt(argc, argv, "ndLh?f:");
4511
        if (c == -1)
4512
            break;
4513
        switch(c) {
4514
        case 'L':
4515
            show_license();
4516
            exit(1);
4517
        case '?':
4518
        case 'h':
4519
            show_help();
4520
            exit(1);
4521
        case 'n':
4522
            no_launch = 1;
4523
            break;
4524
        case 'd':
4525
            ffserver_debug = 1;
4526
            ffserver_daemon = 0;
4527
            break;
4528
        case 'f':
4529
            config_filename = optarg;
4530
            break;
4531
        default:
4532
            exit(2);
4533
        }
4534
    }
4535

    
4536
    putenv("http_proxy");               /* Kill the http_proxy */
4537

    
4538
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4539

    
4540
    /* address on which the server will handle HTTP connections */
4541
    my_http_addr.sin_family = AF_INET;
4542
    my_http_addr.sin_port = htons (8080);
4543
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4544

    
4545
    /* address on which the server will handle RTSP connections */
4546
    my_rtsp_addr.sin_family = AF_INET;
4547
    my_rtsp_addr.sin_port = htons (5454);
4548
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4549

    
4550
    nb_max_connections = 5;
4551
    max_bandwidth = 1000;
4552
    first_stream = NULL;
4553
    logfilename[0] = '\0';
4554

    
4555
    memset(&sigact, 0, sizeof(sigact));
4556
    sigact.sa_handler = handle_child_exit;
4557
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4558
    sigaction(SIGCHLD, &sigact, 0);
4559

    
4560
    if (parse_ffconfig(config_filename) < 0) {
4561
        fprintf(stderr, "Incorrect config file - exiting.\n");
4562
        exit(1);
4563
    }
4564

    
4565
    build_file_streams();
4566

    
4567
    build_feed_streams();
4568

    
4569
    compute_bandwidth();
4570

    
4571
    /* put the process in background and detach it from its TTY */
4572
    if (ffserver_daemon) {
4573
        int pid;
4574

    
4575
        pid = fork();
4576
        if (pid < 0) {
4577
            perror("fork");
4578
            exit(1);
4579
        } else if (pid > 0) {
4580
            /* parent : exit */
4581
            exit(0);
4582
        } else {
4583
            /* child */
4584
            setsid();
4585
            chdir("/");
4586
            close(0);
4587
            open("/dev/null", O_RDWR);
4588
            if (strcmp(logfilename, "-") != 0) {
4589
                close(1);
4590
                dup(0);
4591
            }
4592
            close(2);
4593
            dup(0);
4594
        }
4595
    }
4596

    
4597
    /* signal init */
4598
    signal(SIGPIPE, SIG_IGN);
4599

    
4600
    /* open log file if needed */
4601
    if (logfilename[0] != '\0') {
4602
        if (!strcmp(logfilename, "-"))
4603
            logfile = stdout;
4604
        else
4605
            logfile = fopen(logfilename, "w");
4606
    }
4607

    
4608
    if (http_server() < 0) {
4609
        fprintf(stderr, "Could not start server\n");
4610
        exit(1);
4611
    }
4612

    
4613
    return 0;
4614
}