Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ df1a4b11

History | View | Annotate | Download (149 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

    
22
#define _XOPEN_SOURCE 600
23

    
24
#include "config.h"
25
#ifndef HAVE_CLOSESOCKET
26
#define closesocket close
27
#endif
28
#include <string.h>
29
#include <strings.h>
30
#include <stdlib.h>
31
#include "libavutil/random.h"
32
#include "libavutil/avstring.h"
33
#include "libavformat/avformat.h"
34
#include "libavformat/network.h"
35
#include "libavformat/os_support.h"
36
#include "libavformat/rtp.h"
37
#include "libavformat/rtsp.h"
38
#include "libavcodec/opt.h"
39
#include <stdarg.h>
40
#include <unistd.h>
41
#include <fcntl.h>
42
#include <sys/ioctl.h>
43
#ifdef HAVE_POLL_H
44
#include <poll.h>
45
#endif
46
#include <errno.h>
47
#include <sys/time.h>
48
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
49
#include <time.h>
50
#include <sys/wait.h>
51
#include <signal.h>
52
#ifdef HAVE_DLFCN_H
53
#include <dlfcn.h>
54
#endif
55

    
56
#include "cmdutils.h"
57

    
58
#undef exit
59

    
60
const char program_name[] = "FFserver";
61
const int program_birth_year = 2000;
62

    
63
static const OptionDef options[];
64

    
65
enum HTTPState {
66
    HTTPSTATE_WAIT_REQUEST,
67
    HTTPSTATE_SEND_HEADER,
68
    HTTPSTATE_SEND_DATA_HEADER,
69
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
70
    HTTPSTATE_SEND_DATA_TRAILER,
71
    HTTPSTATE_RECEIVE_DATA,
72
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
73
    HTTPSTATE_READY,
74

    
75
    RTSPSTATE_WAIT_REQUEST,
76
    RTSPSTATE_SEND_REPLY,
77
    RTSPSTATE_SEND_PACKET,
78
};
79

    
80
static const char *http_state[] = {
81
    "HTTP_WAIT_REQUEST",
82
    "HTTP_SEND_HEADER",
83

    
84
    "SEND_DATA_HEADER",
85
    "SEND_DATA",
86
    "SEND_DATA_TRAILER",
87
    "RECEIVE_DATA",
88
    "WAIT_FEED",
89
    "READY",
90

    
91
    "RTSP_WAIT_REQUEST",
92
    "RTSP_SEND_REPLY",
93
    "RTSP_SEND_PACKET",
94
};
95

    
96
#define IOBUFFER_INIT_SIZE 8192
97

    
98
/* timeouts are in ms */
99
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
100
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
101

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

    
104
typedef struct {
105
    int64_t count1, count2;
106
    int64_t time1, time2;
107
} DataRateData;
108

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

    
154
    /* RTSP state specific */
155
    uint8_t *pb_buffer; /* XXX: use that in all the code */
156
    ByteIOContext *pb;
157
    int seq; /* RTSP sequence number */
158

    
159
    /* RTP state specific */
160
    enum RTSPProtocol rtp_protocol;
161
    char session_id[32]; /* session id */
162
    AVFormatContext *rtp_ctx[MAX_STREAMS];
163

    
164
    /* RTP/UDP specific */
165
    URLContext *rtp_handles[MAX_STREAMS];
166

    
167
    /* RTP/TCP specific */
168
    struct HTTPContext *rtsp_c;
169
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170
} HTTPContext;
171

    
172
/* each generated stream is described here */
173
enum StreamType {
174
    STREAM_TYPE_LIVE,
175
    STREAM_TYPE_STATUS,
176
    STREAM_TYPE_REDIRECT,
177
};
178

    
179
enum IPAddressAction {
180
    IP_ALLOW = 1,
181
    IP_DENY,
182
};
183

    
184
typedef struct IPAddressACL {
185
    struct IPAddressACL *next;
186
    enum IPAddressAction action;
187
    /* These are in host order */
188
    struct in_addr first;
189
    struct in_addr last;
190
} IPAddressACL;
191

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

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

    
240
typedef struct FeedData {
241
    long long data_count;
242
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
243
} FeedData;
244

    
245
static struct sockaddr_in my_http_addr;
246
static struct sockaddr_in my_rtsp_addr;
247

    
248
static char logfilename[1024];
249
static HTTPContext *first_http_ctx;
250
static FFStream *first_feed;   /* contains only feeds */
251
static FFStream *first_stream; /* contains all streams, including feeds */
252

    
253
static void new_connection(int server_fd, int is_rtsp);
254
static void close_connection(HTTPContext *c);
255

    
256
/* HTTP handling */
257
static int handle_connection(HTTPContext *c);
258
static int http_parse_request(HTTPContext *c);
259
static int http_send_data(HTTPContext *c);
260
static void compute_status(HTTPContext *c);
261
static int open_input_stream(HTTPContext *c, const char *info);
262
static int http_start_receive_data(HTTPContext *c);
263
static int http_receive_data(HTTPContext *c);
264

    
265
/* RTSP handling */
266
static int rtsp_parse_request(HTTPContext *c);
267
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
268
static void rtsp_cmd_options(HTTPContext *c, const char *url);
269
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
270
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
271
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
272
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
273

    
274
/* SDP handling */
275
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
276
                                   struct in_addr my_ip);
277

    
278
/* RTP handling */
279
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
280
                                       FFStream *stream, const char *session_id,
281
                                       enum RTSPProtocol rtp_protocol);
282
static int rtp_new_av_stream(HTTPContext *c,
283
                             int stream_index, struct sockaddr_in *dest_addr,
284
                             HTTPContext *rtsp_c);
285

    
286
static const char *my_program_name;
287
static const char *my_program_dir;
288

    
289
static const char *config_filename;
290
static int ffserver_debug;
291
static int ffserver_daemon;
292
static int no_launch;
293
static int need_to_start_children;
294

    
295
/* maximum number of simultaneous HTTP connections */
296
static unsigned int nb_max_http_connections = 2000;
297
static unsigned int nb_max_connections = 5;
298
static unsigned int nb_connections;
299

    
300
static uint64_t max_bandwidth = 1000;
301
static uint64_t current_bandwidth;
302

    
303
static int64_t cur_time;           // Making this global saves on passing it around everywhere
304

    
305
static AVRandomState random_state;
306

    
307
static FILE *logfile = NULL;
308

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

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

    
323
static void http_vlog(const char *fmt, va_list vargs)
324
{
325
    static int print_prefix = 1;
326
    if (logfile) {
327
        if (print_prefix) {
328
            char buf[32];
329
            ctime1(buf);
330
            fprintf(logfile, "%s ", buf);
331
        }
332
        print_prefix = strstr(fmt, "\n") != NULL;
333
        vfprintf(logfile, fmt, vargs);
334
        fflush(logfile);
335
    }
336
}
337

    
338
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
339
{
340
    va_list vargs;
341
    va_start(vargs, fmt);
342
    http_vlog(fmt, vargs);
343
    va_end(vargs);
344
}
345

    
346
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
347
{
348
    static int print_prefix = 1;
349
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
350
    if (level > av_log_level)
351
        return;
352
    if (print_prefix && avc)
353
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
354
    print_prefix = strstr(fmt, "\n") != NULL;
355
    http_vlog(fmt, vargs);
356
}
357

    
358
static void log_connection(HTTPContext *c)
359
{
360
    if (c->suppress_log)
361
        return;
362

    
363
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
364
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
365
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
366
}
367

    
368
static void update_datarate(DataRateData *drd, int64_t count)
369
{
370
    if (!drd->time1 && !drd->count1) {
371
        drd->time1 = drd->time2 = cur_time;
372
        drd->count1 = drd->count2 = count;
373
    } else if (cur_time - drd->time2 > 5000) {
374
        drd->time1 = drd->time2;
375
        drd->count1 = drd->count2;
376
        drd->time2 = cur_time;
377
        drd->count2 = count;
378
    }
379
}
380

    
381
/* In bytes per second */
382
static int compute_datarate(DataRateData *drd, int64_t count)
383
{
384
    if (cur_time == drd->time1)
385
        return 0;
386

    
387
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
388
}
389

    
390

    
391
static void start_children(FFStream *feed)
392
{
393
    if (no_launch)
394
        return;
395

    
396
    for (; feed; feed = feed->next) {
397
        if (feed->child_argv && !feed->pid) {
398
            feed->pid_start = time(0);
399

    
400
            feed->pid = fork();
401

    
402
            if (feed->pid < 0) {
403
                http_log("Unable to create children\n");
404
                exit(1);
405
            }
406
            if (!feed->pid) {
407
                /* In child */
408
                char pathname[1024];
409
                char *slash;
410
                int i;
411

    
412
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
413

    
414
                slash = strrchr(pathname, '/');
415
                if (!slash)
416
                    slash = pathname;
417
                else
418
                    slash++;
419
                strcpy(slash, "ffmpeg");
420

    
421
                http_log("Launch commandline: ");
422
                http_log("%s ", pathname);
423
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
424
                    http_log("%s ", feed->child_argv[i]);
425
                http_log("\n");
426

    
427
                for (i = 3; i < 256; i++)
428
                    close(i);
429

    
430
                if (!ffserver_debug) {
431
                    i = open("/dev/null", O_RDWR);
432
                    if (i != -1) {
433
                        dup2(i, 0);
434
                        dup2(i, 1);
435
                        dup2(i, 2);
436
                        close(i);
437
                    }
438
                }
439

    
440
                /* This is needed to make relative pathnames work */
441
                chdir(my_program_dir);
442

    
443
                signal(SIGPIPE, SIG_DFL);
444

    
445
                execvp(pathname, feed->child_argv);
446

    
447
                _exit(1);
448
            }
449
        }
450
    }
451
}
452

    
453
/* open a listening socket */
454
static int socket_open_listen(struct sockaddr_in *my_addr)
455
{
456
    int server_fd, tmp;
457

    
458
    server_fd = socket(AF_INET,SOCK_STREAM,0);
459
    if (server_fd < 0) {
460
        perror ("socket");
461
        return -1;
462
    }
463

    
464
    tmp = 1;
465
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
466

    
467
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
468
        char bindmsg[32];
469
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
470
        perror (bindmsg);
471
        closesocket(server_fd);
472
        return -1;
473
    }
474

    
475
    if (listen (server_fd, 5) < 0) {
476
        perror ("listen");
477
        closesocket(server_fd);
478
        return -1;
479
    }
480
    ff_socket_nonblock(server_fd, 1);
481

    
482
    return server_fd;
483
}
484

    
485
/* start all multicast streams */
486
static void start_multicast(void)
487
{
488
    FFStream *stream;
489
    char session_id[32];
490
    HTTPContext *rtp_c;
491
    struct sockaddr_in dest_addr;
492
    int default_port, stream_index;
493

    
494
    default_port = 6000;
495
    for(stream = first_stream; stream != NULL; stream = stream->next) {
496
        if (stream->is_multicast) {
497
            /* open the RTP connection */
498
            snprintf(session_id, sizeof(session_id), "%08x%08x",
499
                     av_random(&random_state), av_random(&random_state));
500

    
501
            /* choose a port if none given */
502
            if (stream->multicast_port == 0) {
503
                stream->multicast_port = default_port;
504
                default_port += 100;
505
            }
506

    
507
            dest_addr.sin_family = AF_INET;
508
            dest_addr.sin_addr = stream->multicast_ip;
509
            dest_addr.sin_port = htons(stream->multicast_port);
510

    
511
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
512
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
513
            if (!rtp_c)
514
                continue;
515

    
516
            if (open_input_stream(rtp_c, "") < 0) {
517
                http_log("Could not open input stream for stream '%s'\n",
518
                         stream->filename);
519
                continue;
520
            }
521

    
522
            /* open each RTP stream */
523
            for(stream_index = 0; stream_index < stream->nb_streams;
524
                stream_index++) {
525
                dest_addr.sin_port = htons(stream->multicast_port +
526
                                           2 * stream_index);
527
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
528
                    http_log("Could not open output stream '%s/streamid=%d'\n",
529
                             stream->filename, stream_index);
530
                    exit(1);
531
                }
532
            }
533

    
534
            /* change state to send data */
535
            rtp_c->state = HTTPSTATE_SEND_DATA;
536
        }
537
    }
538
}
539

    
540
/* main loop of the http server */
541
static int http_server(void)
542
{
543
    int server_fd = 0, rtsp_server_fd = 0;
544
    int ret, delay, delay1;
545
    struct pollfd *poll_table, *poll_entry;
546
    HTTPContext *c, *c_next;
547

    
548
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
549
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
550
        return -1;
551
    }
552

    
553
    if (my_http_addr.sin_port) {
554
        server_fd = socket_open_listen(&my_http_addr);
555
        if (server_fd < 0)
556
            return -1;
557
    }
558

    
559
    if (my_rtsp_addr.sin_port) {
560
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
561
        if (rtsp_server_fd < 0)
562
            return -1;
563
    }
564

    
565
    if (!rtsp_server_fd && !server_fd) {
566
        http_log("HTTP and RTSP disabled.\n");
567
        return -1;
568
    }
569

    
570
    http_log("ffserver started.\n");
571

    
572
    start_children(first_feed);
573

    
574
    start_multicast();
575

    
576
    for(;;) {
577
        poll_entry = poll_table;
578
        if (server_fd) {
579
            poll_entry->fd = server_fd;
580
            poll_entry->events = POLLIN;
581
            poll_entry++;
582
        }
583
        if (rtsp_server_fd) {
584
            poll_entry->fd = rtsp_server_fd;
585
            poll_entry->events = POLLIN;
586
            poll_entry++;
587
        }
588

    
589
        /* wait for events on each HTTP handle */
590
        c = first_http_ctx;
591
        delay = 1000;
592
        while (c != NULL) {
593
            int fd;
594
            fd = c->fd;
595
            switch(c->state) {
596
            case HTTPSTATE_SEND_HEADER:
597
            case RTSPSTATE_SEND_REPLY:
598
            case RTSPSTATE_SEND_PACKET:
599
                c->poll_entry = poll_entry;
600
                poll_entry->fd = fd;
601
                poll_entry->events = POLLOUT;
602
                poll_entry++;
603
                break;
604
            case HTTPSTATE_SEND_DATA_HEADER:
605
            case HTTPSTATE_SEND_DATA:
606
            case HTTPSTATE_SEND_DATA_TRAILER:
607
                if (!c->is_packetized) {
608
                    /* for TCP, we output as much as we can (may need to put a limit) */
609
                    c->poll_entry = poll_entry;
610
                    poll_entry->fd = fd;
611
                    poll_entry->events = POLLOUT;
612
                    poll_entry++;
613
                } else {
614
                    /* when ffserver is doing the timing, we work by
615
                       looking at which packet need to be sent every
616
                       10 ms */
617
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
618
                    if (delay1 < delay)
619
                        delay = delay1;
620
                }
621
                break;
622
            case HTTPSTATE_WAIT_REQUEST:
623
            case HTTPSTATE_RECEIVE_DATA:
624
            case HTTPSTATE_WAIT_FEED:
625
            case RTSPSTATE_WAIT_REQUEST:
626
                /* need to catch errors */
627
                c->poll_entry = poll_entry;
628
                poll_entry->fd = fd;
629
                poll_entry->events = POLLIN;/* Maybe this will work */
630
                poll_entry++;
631
                break;
632
            default:
633
                c->poll_entry = NULL;
634
                break;
635
            }
636
            c = c->next;
637
        }
638

    
639
        /* wait for an event on one connection. We poll at least every
640
           second to handle timeouts */
641
        do {
642
            ret = poll(poll_table, poll_entry - poll_table, delay);
643
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
644
                ff_neterrno() != FF_NETERROR(EINTR))
645
                return -1;
646
        } while (ret < 0);
647

    
648
        cur_time = av_gettime() / 1000;
649

    
650
        if (need_to_start_children) {
651
            need_to_start_children = 0;
652
            start_children(first_feed);
653
        }
654

    
655
        /* now handle the events */
656
        for(c = first_http_ctx; c != NULL; c = c_next) {
657
            c_next = c->next;
658
            if (handle_connection(c) < 0) {
659
                /* close and free the connection */
660
                log_connection(c);
661
                close_connection(c);
662
            }
663
        }
664

    
665
        poll_entry = poll_table;
666
        if (server_fd) {
667
            /* new HTTP connection request ? */
668
            if (poll_entry->revents & POLLIN)
669
                new_connection(server_fd, 0);
670
            poll_entry++;
671
        }
672
        if (rtsp_server_fd) {
673
            /* new RTSP connection request ? */
674
            if (poll_entry->revents & POLLIN)
675
                new_connection(rtsp_server_fd, 1);
676
        }
677
    }
678
}
679

    
680
/* start waiting for a new HTTP/RTSP request */
681
static void start_wait_request(HTTPContext *c, int is_rtsp)
682
{
683
    c->buffer_ptr = c->buffer;
684
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
685

    
686
    if (is_rtsp) {
687
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
688
        c->state = RTSPSTATE_WAIT_REQUEST;
689
    } else {
690
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
691
        c->state = HTTPSTATE_WAIT_REQUEST;
692
    }
693
}
694

    
695
static void new_connection(int server_fd, int is_rtsp)
696
{
697
    struct sockaddr_in from_addr;
698
    int fd, len;
699
    HTTPContext *c = NULL;
700

    
701
    len = sizeof(from_addr);
702
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
703
                &len);
704
    if (fd < 0) {
705
        http_log("error during accept %s\n", strerror(errno));
706
        return;
707
    }
708
    ff_socket_nonblock(fd, 1);
709

    
710
    /* XXX: should output a warning page when coming
711
       close to the connection limit */
712
    if (nb_connections >= nb_max_connections)
713
        goto fail;
714

    
715
    /* add a new connection */
716
    c = av_mallocz(sizeof(HTTPContext));
717
    if (!c)
718
        goto fail;
719

    
720
    c->fd = fd;
721
    c->poll_entry = NULL;
722
    c->from_addr = from_addr;
723
    c->buffer_size = IOBUFFER_INIT_SIZE;
724
    c->buffer = av_malloc(c->buffer_size);
725
    if (!c->buffer)
726
        goto fail;
727

    
728
    c->next = first_http_ctx;
729
    first_http_ctx = c;
730
    nb_connections++;
731

    
732
    start_wait_request(c, is_rtsp);
733

    
734
    return;
735

    
736
 fail:
737
    if (c) {
738
        av_free(c->buffer);
739
        av_free(c);
740
    }
741
    closesocket(fd);
742
}
743

    
744
static void close_connection(HTTPContext *c)
745
{
746
    HTTPContext **cp, *c1;
747
    int i, nb_streams;
748
    AVFormatContext *ctx;
749
    URLContext *h;
750
    AVStream *st;
751

    
752
    /* remove connection from list */
753
    cp = &first_http_ctx;
754
    while ((*cp) != NULL) {
755
        c1 = *cp;
756
        if (c1 == c)
757
            *cp = c->next;
758
        else
759
            cp = &c1->next;
760
    }
761

    
762
    /* remove references, if any (XXX: do it faster) */
763
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
764
        if (c1->rtsp_c == c)
765
            c1->rtsp_c = NULL;
766
    }
767

    
768
    /* remove connection associated resources */
769
    if (c->fd >= 0)
770
        closesocket(c->fd);
771
    if (c->fmt_in) {
772
        /* close each frame parser */
773
        for(i=0;i<c->fmt_in->nb_streams;i++) {
774
            st = c->fmt_in->streams[i];
775
            if (st->codec->codec)
776
                avcodec_close(st->codec);
777
        }
778
        av_close_input_file(c->fmt_in);
779
    }
780

    
781
    /* free RTP output streams if any */
782
    nb_streams = 0;
783
    if (c->stream)
784
        nb_streams = c->stream->nb_streams;
785

    
786
    for(i=0;i<nb_streams;i++) {
787
        ctx = c->rtp_ctx[i];
788
        if (ctx) {
789
            av_write_trailer(ctx);
790
            av_free(ctx);
791
        }
792
        h = c->rtp_handles[i];
793
        if (h)
794
            url_close(h);
795
    }
796

    
797
    ctx = &c->fmt_ctx;
798

    
799
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
800
        if (ctx->oformat) {
801
            /* prepare header */
802
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
803
                av_write_trailer(ctx);
804
                av_freep(&c->pb_buffer);
805
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
806
            }
807
        }
808
    }
809

    
810
    for(i=0; i<ctx->nb_streams; i++)
811
        av_free(ctx->streams[i]);
812

    
813
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
814
        current_bandwidth -= c->stream->bandwidth;
815

    
816
    /* signal that there is no feed if we are the feeder socket */
817
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
818
        c->stream->feed_opened = 0;
819
        close(c->feed_fd);
820
    }
821

    
822
    av_freep(&c->pb_buffer);
823
    av_freep(&c->packet_buffer);
824
    av_free(c->buffer);
825
    av_free(c);
826
    nb_connections--;
827
}
828

    
829
static int handle_connection(HTTPContext *c)
830
{
831
    int len, ret;
832

    
833
    switch(c->state) {
834
    case HTTPSTATE_WAIT_REQUEST:
835
    case RTSPSTATE_WAIT_REQUEST:
836
        /* timeout ? */
837
        if ((c->timeout - cur_time) < 0)
838
            return -1;
839
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
840
            return -1;
841

    
842
        /* no need to read if no events */
843
        if (!(c->poll_entry->revents & POLLIN))
844
            return 0;
845
        /* read the data */
846
    read_loop:
847
        len = recv(c->fd, c->buffer_ptr, 1, 0);
848
        if (len < 0) {
849
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
850
                ff_neterrno() != FF_NETERROR(EINTR))
851
                return -1;
852
        } else if (len == 0) {
853
            return -1;
854
        } else {
855
            /* search for end of request. */
856
            uint8_t *ptr;
857
            c->buffer_ptr += len;
858
            ptr = c->buffer_ptr;
859
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
860
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
861
                /* request found : parse it and reply */
862
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
863
                    ret = http_parse_request(c);
864
                } else {
865
                    ret = rtsp_parse_request(c);
866
                }
867
                if (ret < 0)
868
                    return -1;
869
            } else if (ptr >= c->buffer_end) {
870
                /* request too long: cannot do anything */
871
                return -1;
872
            } else goto read_loop;
873
        }
874
        break;
875

    
876
    case HTTPSTATE_SEND_HEADER:
877
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
878
            return -1;
879

    
880
        /* no need to write if no events */
881
        if (!(c->poll_entry->revents & POLLOUT))
882
            return 0;
883
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
884
        if (len < 0) {
885
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
886
                ff_neterrno() != FF_NETERROR(EINTR)) {
887
                /* error : close connection */
888
                av_freep(&c->pb_buffer);
889
                return -1;
890
            }
891
        } else {
892
            c->buffer_ptr += len;
893
            if (c->stream)
894
                c->stream->bytes_served += len;
895
            c->data_count += len;
896
            if (c->buffer_ptr >= c->buffer_end) {
897
                av_freep(&c->pb_buffer);
898
                /* if error, exit */
899
                if (c->http_error)
900
                    return -1;
901
                /* all the buffer was sent : synchronize to the incoming stream */
902
                c->state = HTTPSTATE_SEND_DATA_HEADER;
903
                c->buffer_ptr = c->buffer_end = c->buffer;
904
            }
905
        }
906
        break;
907

    
908
    case HTTPSTATE_SEND_DATA:
909
    case HTTPSTATE_SEND_DATA_HEADER:
910
    case HTTPSTATE_SEND_DATA_TRAILER:
911
        /* for packetized output, we consider we can always write (the
912
           input streams sets the speed). It may be better to verify
913
           that we do not rely too much on the kernel queues */
914
        if (!c->is_packetized) {
915
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
916
                return -1;
917

    
918
            /* no need to read if no events */
919
            if (!(c->poll_entry->revents & POLLOUT))
920
                return 0;
921
        }
922
        if (http_send_data(c) < 0)
923
            return -1;
924
        /* close connection if trailer sent */
925
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
926
            return -1;
927
        break;
928
    case HTTPSTATE_RECEIVE_DATA:
929
        /* no need to read if no events */
930
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
931
            return -1;
932
        if (!(c->poll_entry->revents & POLLIN))
933
            return 0;
934
        if (http_receive_data(c) < 0)
935
            return -1;
936
        break;
937
    case HTTPSTATE_WAIT_FEED:
938
        /* no need to read if no events */
939
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
940
            return -1;
941

    
942
        /* nothing to do, we'll be waken up by incoming feed packets */
943
        break;
944

    
945
    case RTSPSTATE_SEND_REPLY:
946
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
947
            av_freep(&c->pb_buffer);
948
            return -1;
949
        }
950
        /* no need to write if no events */
951
        if (!(c->poll_entry->revents & POLLOUT))
952
            return 0;
953
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
954
        if (len < 0) {
955
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
956
                ff_neterrno() != FF_NETERROR(EINTR)) {
957
                /* error : close connection */
958
                av_freep(&c->pb_buffer);
959
                return -1;
960
            }
961
        } else {
962
            c->buffer_ptr += len;
963
            c->data_count += len;
964
            if (c->buffer_ptr >= c->buffer_end) {
965
                /* all the buffer was sent : wait for a new request */
966
                av_freep(&c->pb_buffer);
967
                start_wait_request(c, 1);
968
            }
969
        }
970
        break;
971
    case RTSPSTATE_SEND_PACKET:
972
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
973
            av_freep(&c->packet_buffer);
974
            return -1;
975
        }
976
        /* no need to write if no events */
977
        if (!(c->poll_entry->revents & POLLOUT))
978
            return 0;
979
        len = send(c->fd, c->packet_buffer_ptr,
980
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
981
        if (len < 0) {
982
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
983
                ff_neterrno() != FF_NETERROR(EINTR)) {
984
                /* error : close connection */
985
                av_freep(&c->packet_buffer);
986
                return -1;
987
            }
988
        } else {
989
            c->packet_buffer_ptr += len;
990
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
991
                /* all the buffer was sent : wait for a new request */
992
                av_freep(&c->packet_buffer);
993
                c->state = RTSPSTATE_WAIT_REQUEST;
994
            }
995
        }
996
        break;
997
    case HTTPSTATE_READY:
998
        /* nothing to do */
999
        break;
1000
    default:
1001
        return -1;
1002
    }
1003
    return 0;
1004
}
1005

    
1006
static int extract_rates(char *rates, int ratelen, const char *request)
1007
{
1008
    const char *p;
1009

    
1010
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1011
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1012
            const char *q = p + 7;
1013

    
1014
            while (*q && *q != '\n' && isspace(*q))
1015
                q++;
1016

    
1017
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1018
                int stream_no;
1019
                int rate_no;
1020

    
1021
                q += 20;
1022

    
1023
                memset(rates, 0xff, ratelen);
1024

    
1025
                while (1) {
1026
                    while (*q && *q != '\n' && *q != ':')
1027
                        q++;
1028

    
1029
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1030
                        break;
1031

    
1032
                    stream_no--;
1033
                    if (stream_no < ratelen && stream_no >= 0)
1034
                        rates[stream_no] = rate_no;
1035

    
1036
                    while (*q && *q != '\n' && !isspace(*q))
1037
                        q++;
1038
                }
1039

    
1040
                return 1;
1041
            }
1042
        }
1043
        p = strchr(p, '\n');
1044
        if (!p)
1045
            break;
1046

    
1047
        p++;
1048
    }
1049

    
1050
    return 0;
1051
}
1052

    
1053
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1054
{
1055
    int i;
1056
    int best_bitrate = 100000000;
1057
    int best = -1;
1058

    
1059
    for (i = 0; i < feed->nb_streams; i++) {
1060
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1061

    
1062
        if (feed_codec->codec_id != codec->codec_id ||
1063
            feed_codec->sample_rate != codec->sample_rate ||
1064
            feed_codec->width != codec->width ||
1065
            feed_codec->height != codec->height)
1066
            continue;
1067

    
1068
        /* Potential stream */
1069

    
1070
        /* We want the fastest stream less than bit_rate, or the slowest
1071
         * faster than bit_rate
1072
         */
1073

    
1074
        if (feed_codec->bit_rate <= bit_rate) {
1075
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1076
                best_bitrate = feed_codec->bit_rate;
1077
                best = i;
1078
            }
1079
        } else {
1080
            if (feed_codec->bit_rate < best_bitrate) {
1081
                best_bitrate = feed_codec->bit_rate;
1082
                best = i;
1083
            }
1084
        }
1085
    }
1086

    
1087
    return best;
1088
}
1089

    
1090
static int modify_current_stream(HTTPContext *c, char *rates)
1091
{
1092
    int i;
1093
    FFStream *req = c->stream;
1094
    int action_required = 0;
1095

    
1096
    /* Not much we can do for a feed */
1097
    if (!req->feed)
1098
        return 0;
1099

    
1100
    for (i = 0; i < req->nb_streams; i++) {
1101
        AVCodecContext *codec = req->streams[i]->codec;
1102

    
1103
        switch(rates[i]) {
1104
            case 0:
1105
                c->switch_feed_streams[i] = req->feed_streams[i];
1106
                break;
1107
            case 1:
1108
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1109
                break;
1110
            case 2:
1111
                /* Wants off or slow */
1112
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1113
#ifdef WANTS_OFF
1114
                /* This doesn't work well when it turns off the only stream! */
1115
                c->switch_feed_streams[i] = -2;
1116
                c->feed_streams[i] = -2;
1117
#endif
1118
                break;
1119
        }
1120

    
1121
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1122
            action_required = 1;
1123
    }
1124

    
1125
    return action_required;
1126
}
1127

    
1128

    
1129
static void do_switch_stream(HTTPContext *c, int i)
1130
{
1131
    if (c->switch_feed_streams[i] >= 0) {
1132
#ifdef PHILIP
1133
        c->feed_streams[i] = c->switch_feed_streams[i];
1134
#endif
1135

    
1136
        /* Now update the stream */
1137
    }
1138
    c->switch_feed_streams[i] = -1;
1139
}
1140

    
1141
/* XXX: factorize in utils.c ? */
1142
/* XXX: take care with different space meaning */
1143
static void skip_spaces(const char **pp)
1144
{
1145
    const char *p;
1146
    p = *pp;
1147
    while (*p == ' ' || *p == '\t')
1148
        p++;
1149
    *pp = p;
1150
}
1151

    
1152
static void get_word(char *buf, int buf_size, const char **pp)
1153
{
1154
    const char *p;
1155
    char *q;
1156

    
1157
    p = *pp;
1158
    skip_spaces(&p);
1159
    q = buf;
1160
    while (!isspace(*p) && *p != '\0') {
1161
        if ((q - buf) < buf_size - 1)
1162
            *q++ = *p;
1163
        p++;
1164
    }
1165
    if (buf_size > 0)
1166
        *q = '\0';
1167
    *pp = p;
1168
}
1169

    
1170
static int validate_acl(FFStream *stream, HTTPContext *c)
1171
{
1172
    enum IPAddressAction last_action = IP_DENY;
1173
    IPAddressACL *acl;
1174
    struct in_addr *src = &c->from_addr.sin_addr;
1175
    unsigned long src_addr = src->s_addr;
1176

    
1177
    for (acl = stream->acl; acl; acl = acl->next) {
1178
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1179
            return (acl->action == IP_ALLOW) ? 1 : 0;
1180
        last_action = acl->action;
1181
    }
1182

    
1183
    /* Nothing matched, so return not the last action */
1184
    return (last_action == IP_DENY) ? 1 : 0;
1185
}
1186

    
1187
/* compute the real filename of a file by matching it without its
1188
   extensions to all the stream filenames */
1189
static void compute_real_filename(char *filename, int max_size)
1190
{
1191
    char file1[1024];
1192
    char file2[1024];
1193
    char *p;
1194
    FFStream *stream;
1195

    
1196
    /* compute filename by matching without the file extensions */
1197
    av_strlcpy(file1, filename, sizeof(file1));
1198
    p = strrchr(file1, '.');
1199
    if (p)
1200
        *p = '\0';
1201
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1202
        av_strlcpy(file2, stream->filename, sizeof(file2));
1203
        p = strrchr(file2, '.');
1204
        if (p)
1205
            *p = '\0';
1206
        if (!strcmp(file1, file2)) {
1207
            av_strlcpy(filename, stream->filename, max_size);
1208
            break;
1209
        }
1210
    }
1211
}
1212

    
1213
enum RedirType {
1214
    REDIR_NONE,
1215
    REDIR_ASX,
1216
    REDIR_RAM,
1217
    REDIR_ASF,
1218
    REDIR_RTSP,
1219
    REDIR_SDP,
1220
};
1221

    
1222
/* parse http request and prepare header */
1223
static int http_parse_request(HTTPContext *c)
1224
{
1225
    char *p;
1226
    enum RedirType redir_type;
1227
    char cmd[32];
1228
    char info[1024], filename[1024];
1229
    char url[1024], *q;
1230
    char protocol[32];
1231
    char msg[1024];
1232
    const char *mime_type;
1233
    FFStream *stream;
1234
    int i;
1235
    char ratebuf[32];
1236
    char *useragent = 0;
1237

    
1238
    p = c->buffer;
1239
    get_word(cmd, sizeof(cmd), (const char **)&p);
1240
    av_strlcpy(c->method, cmd, sizeof(c->method));
1241

    
1242
    if (!strcmp(cmd, "GET"))
1243
        c->post = 0;
1244
    else if (!strcmp(cmd, "POST"))
1245
        c->post = 1;
1246
    else
1247
        return -1;
1248

    
1249
    get_word(url, sizeof(url), (const char **)&p);
1250
    av_strlcpy(c->url, url, sizeof(c->url));
1251

    
1252
    get_word(protocol, sizeof(protocol), (const char **)&p);
1253
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1254
        return -1;
1255

    
1256
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1257

    
1258
    if (ffserver_debug)
1259
        http_log("New connection: %s %s\n", cmd, url);
1260

    
1261
    /* find the filename and the optional info string in the request */
1262
    p = strchr(url, '?');
1263
    if (p) {
1264
        av_strlcpy(info, p, sizeof(info));
1265
        *p = '\0';
1266
    } else
1267
        info[0] = '\0';
1268

    
1269
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1270

    
1271
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1272
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1273
            useragent = p + 11;
1274
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1275
                useragent++;
1276
            break;
1277
        }
1278
        p = strchr(p, '\n');
1279
        if (!p)
1280
            break;
1281

    
1282
        p++;
1283
    }
1284

    
1285
    redir_type = REDIR_NONE;
1286
    if (match_ext(filename, "asx")) {
1287
        redir_type = REDIR_ASX;
1288
        filename[strlen(filename)-1] = 'f';
1289
    } else if (match_ext(filename, "asf") &&
1290
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1291
        /* if this isn't WMP or lookalike, return the redirector file */
1292
        redir_type = REDIR_ASF;
1293
    } else if (match_ext(filename, "rpm,ram")) {
1294
        redir_type = REDIR_RAM;
1295
        strcpy(filename + strlen(filename)-2, "m");
1296
    } else if (match_ext(filename, "rtsp")) {
1297
        redir_type = REDIR_RTSP;
1298
        compute_real_filename(filename, sizeof(filename) - 1);
1299
    } else if (match_ext(filename, "sdp")) {
1300
        redir_type = REDIR_SDP;
1301
        compute_real_filename(filename, sizeof(filename) - 1);
1302
    }
1303

    
1304
    // "redirect" / request to index.html
1305
    if (!strlen(filename))
1306
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1307

    
1308
    stream = first_stream;
1309
    while (stream != NULL) {
1310
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1311
            break;
1312
        stream = stream->next;
1313
    }
1314
    if (stream == NULL) {
1315
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1316
        goto send_error;
1317
    }
1318

    
1319
    c->stream = stream;
1320
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1321
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1322

    
1323
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1324
        c->http_error = 301;
1325
        q = c->buffer;
1326
        q += snprintf(q, c->buffer_size,
1327
                      "HTTP/1.0 301 Moved\r\n"
1328
                      "Location: %s\r\n"
1329
                      "Content-type: text/html\r\n"
1330
                      "\r\n"
1331
                      "<html><head><title>Moved</title></head><body>\r\n"
1332
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1333
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1334
        /* prepare output buffer */
1335
        c->buffer_ptr = c->buffer;
1336
        c->buffer_end = q;
1337
        c->state = HTTPSTATE_SEND_HEADER;
1338
        return 0;
1339
    }
1340

    
1341
    /* If this is WMP, get the rate information */
1342
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1343
        if (modify_current_stream(c, ratebuf)) {
1344
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1345
                if (c->switch_feed_streams[i] >= 0)
1346
                    do_switch_stream(c, i);
1347
            }
1348
        }
1349
    }
1350

    
1351
    /* If already streaming this feed, do not let start another feeder. */
1352
    if (stream->feed_opened) {
1353
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1354
        http_log("feed %s already being received\n", stream->feed_filename);
1355
        goto send_error;
1356
    }
1357

    
1358
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1359
        current_bandwidth += stream->bandwidth;
1360

    
1361
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1362
        c->http_error = 200;
1363
        q = c->buffer;
1364
        q += snprintf(q, c->buffer_size,
1365
                      "HTTP/1.0 200 Server too busy\r\n"
1366
                      "Content-type: text/html\r\n"
1367
                      "\r\n"
1368
                      "<html><head><title>Too busy</title></head><body>\r\n"
1369
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1370
                      "<p>The bandwidth being served (including your stream) is %lldkbit/sec, "
1371
                      "and this exceeds the limit of %lldkbit/sec.</p>\r\n"
1372
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1373
        /* prepare output buffer */
1374
        c->buffer_ptr = c->buffer;
1375
        c->buffer_end = q;
1376
        c->state = HTTPSTATE_SEND_HEADER;
1377
        return 0;
1378
    }
1379

    
1380
    if (redir_type != REDIR_NONE) {
1381
        char *hostinfo = 0;
1382

    
1383
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1384
            if (strncasecmp(p, "Host:", 5) == 0) {
1385
                hostinfo = p + 5;
1386
                break;
1387
            }
1388
            p = strchr(p, '\n');
1389
            if (!p)
1390
                break;
1391

    
1392
            p++;
1393
        }
1394

    
1395
        if (hostinfo) {
1396
            char *eoh;
1397
            char hostbuf[260];
1398

    
1399
            while (isspace(*hostinfo))
1400
                hostinfo++;
1401

    
1402
            eoh = strchr(hostinfo, '\n');
1403
            if (eoh) {
1404
                if (eoh[-1] == '\r')
1405
                    eoh--;
1406

    
1407
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1408
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1409
                    hostbuf[eoh - hostinfo] = 0;
1410

    
1411
                    c->http_error = 200;
1412
                    q = c->buffer;
1413
                    switch(redir_type) {
1414
                    case REDIR_ASX:
1415
                        q += snprintf(q, c->buffer_size,
1416
                                      "HTTP/1.0 200 ASX Follows\r\n"
1417
                                      "Content-type: video/x-ms-asf\r\n"
1418
                                      "\r\n"
1419
                                      "<ASX Version=\"3\">\r\n"
1420
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1421
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1422
                                      "</ASX>\r\n", hostbuf, filename, info);
1423
                        break;
1424
                    case REDIR_RAM:
1425
                        q += snprintf(q, c->buffer_size,
1426
                                      "HTTP/1.0 200 RAM Follows\r\n"
1427
                                      "Content-type: audio/x-pn-realaudio\r\n"
1428
                                      "\r\n"
1429
                                      "# Autogenerated by ffserver\r\n"
1430
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1431
                        break;
1432
                    case REDIR_ASF:
1433
                        q += snprintf(q, c->buffer_size,
1434
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1435
                                      "Content-type: video/x-ms-asf\r\n"
1436
                                      "\r\n"
1437
                                      "[Reference]\r\n"
1438
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1439
                        break;
1440
                    case REDIR_RTSP:
1441
                        {
1442
                            char hostname[256], *p;
1443
                            /* extract only hostname */
1444
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1445
                            p = strrchr(hostname, ':');
1446
                            if (p)
1447
                                *p = '\0';
1448
                            q += snprintf(q, c->buffer_size,
1449
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1450
                                          /* XXX: incorrect mime type ? */
1451
                                          "Content-type: application/x-rtsp\r\n"
1452
                                          "\r\n"
1453
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1454
                        }
1455
                        break;
1456
                    case REDIR_SDP:
1457
                        {
1458
                            uint8_t *sdp_data;
1459
                            int sdp_data_size, len;
1460
                            struct sockaddr_in my_addr;
1461

    
1462
                            q += snprintf(q, c->buffer_size,
1463
                                          "HTTP/1.0 200 OK\r\n"
1464
                                          "Content-type: application/sdp\r\n"
1465
                                          "\r\n");
1466

    
1467
                            len = sizeof(my_addr);
1468
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1469

    
1470
                            /* XXX: should use a dynamic buffer */
1471
                            sdp_data_size = prepare_sdp_description(stream,
1472
                                                                    &sdp_data,
1473
                                                                    my_addr.sin_addr);
1474
                            if (sdp_data_size > 0) {
1475
                                memcpy(q, sdp_data, sdp_data_size);
1476
                                q += sdp_data_size;
1477
                                *q = '\0';
1478
                                av_free(sdp_data);
1479
                            }
1480
                        }
1481
                        break;
1482
                    default:
1483
                        abort();
1484
                        break;
1485
                    }
1486

    
1487
                    /* prepare output buffer */
1488
                    c->buffer_ptr = c->buffer;
1489
                    c->buffer_end = q;
1490
                    c->state = HTTPSTATE_SEND_HEADER;
1491
                    return 0;
1492
                }
1493
            }
1494
        }
1495

    
1496
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1497
        goto send_error;
1498
    }
1499

    
1500
    stream->conns_served++;
1501

    
1502
    /* XXX: add there authenticate and IP match */
1503

    
1504
    if (c->post) {
1505
        /* if post, it means a feed is being sent */
1506
        if (!stream->is_feed) {
1507
            /* However it might be a status report from WMP! Let us log the
1508
             * data as it might come in handy one day. */
1509
            char *logline = 0;
1510
            int client_id = 0;
1511

    
1512
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1513
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1514
                    logline = p;
1515
                    break;
1516
                }
1517
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1518
                    client_id = strtol(p + 18, 0, 10);
1519
                p = strchr(p, '\n');
1520
                if (!p)
1521
                    break;
1522

    
1523
                p++;
1524
            }
1525

    
1526
            if (logline) {
1527
                char *eol = strchr(logline, '\n');
1528

    
1529
                logline += 17;
1530

    
1531
                if (eol) {
1532
                    if (eol[-1] == '\r')
1533
                        eol--;
1534
                    http_log("%.*s\n", (int) (eol - logline), logline);
1535
                    c->suppress_log = 1;
1536
                }
1537
            }
1538

    
1539
#ifdef DEBUG_WMP
1540
            http_log("\nGot request:\n%s\n", c->buffer);
1541
#endif
1542

    
1543
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1544
                HTTPContext *wmpc;
1545

    
1546
                /* Now we have to find the client_id */
1547
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1548
                    if (wmpc->wmp_client_id == client_id)
1549
                        break;
1550
                }
1551

    
1552
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1553
                    wmpc->switch_pending = 1;
1554
            }
1555

    
1556
            snprintf(msg, sizeof(msg), "POST command not handled");
1557
            c->stream = 0;
1558
            goto send_error;
1559
        }
1560
        if (http_start_receive_data(c) < 0) {
1561
            snprintf(msg, sizeof(msg), "could not open feed");
1562
            goto send_error;
1563
        }
1564
        c->http_error = 0;
1565
        c->state = HTTPSTATE_RECEIVE_DATA;
1566
        return 0;
1567
    }
1568

    
1569
#ifdef DEBUG_WMP
1570
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1571
        http_log("\nGot request:\n%s\n", c->buffer);
1572
#endif
1573

    
1574
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1575
        goto send_status;
1576

    
1577
    /* open input stream */
1578
    if (open_input_stream(c, info) < 0) {
1579
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1580
        goto send_error;
1581
    }
1582

    
1583
    /* prepare http header */
1584
    q = c->buffer;
1585
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1586
    mime_type = c->stream->fmt->mime_type;
1587
    if (!mime_type)
1588
        mime_type = "application/x-octet-stream";
1589
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1590

    
1591
    /* for asf, we need extra headers */
1592
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1593
        /* Need to allocate a client id */
1594

    
1595
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1596

    
1597
        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);
1598
    }
1599
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1600
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1601

    
1602
    /* prepare output buffer */
1603
    c->http_error = 0;
1604
    c->buffer_ptr = c->buffer;
1605
    c->buffer_end = q;
1606
    c->state = HTTPSTATE_SEND_HEADER;
1607
    return 0;
1608
 send_error:
1609
    c->http_error = 404;
1610
    q = c->buffer;
1611
    q += snprintf(q, c->buffer_size,
1612
                  "HTTP/1.0 404 Not Found\r\n"
1613
                  "Content-type: text/html\r\n"
1614
                  "\r\n"
1615
                  "<HTML>\n"
1616
                  "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
1617
                  "<BODY>%s</BODY>\n"
1618
                  "</HTML>\n", msg);
1619
    /* prepare output buffer */
1620
    c->buffer_ptr = c->buffer;
1621
    c->buffer_end = q;
1622
    c->state = HTTPSTATE_SEND_HEADER;
1623
    return 0;
1624
 send_status:
1625
    compute_status(c);
1626
    c->http_error = 200; /* horrible : we use this value to avoid
1627
                            going to the send data state */
1628
    c->state = HTTPSTATE_SEND_HEADER;
1629
    return 0;
1630
}
1631

    
1632
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1633
{
1634
    static const char *suffix = " kMGTP";
1635
    const char *s;
1636

    
1637
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1638

    
1639
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1640
}
1641

    
1642
static void compute_status(HTTPContext *c)
1643
{
1644
    HTTPContext *c1;
1645
    FFStream *stream;
1646
    char *p;
1647
    time_t ti;
1648
    int i, len;
1649
    ByteIOContext *pb;
1650

    
1651
    if (url_open_dyn_buf(&pb) < 0) {
1652
        /* XXX: return an error ? */
1653
        c->buffer_ptr = c->buffer;
1654
        c->buffer_end = c->buffer;
1655
        return;
1656
    }
1657

    
1658
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1659
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1660
    url_fprintf(pb, "Pragma: no-cache\r\n");
1661
    url_fprintf(pb, "\r\n");
1662

    
1663
    url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
1664
    if (c->stream->feed_filename[0])
1665
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1666
    url_fprintf(pb, "</HEAD>\n<BODY>");
1667
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1668
    /* format status */
1669
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1670
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1671
    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");
1672
    stream = first_stream;
1673
    while (stream != NULL) {
1674
        char sfilename[1024];
1675
        char *eosf;
1676

    
1677
        if (stream->feed != stream) {
1678
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1679
            eosf = sfilename + strlen(sfilename);
1680
            if (eosf - sfilename >= 4) {
1681
                if (strcmp(eosf - 4, ".asf") == 0)
1682
                    strcpy(eosf - 4, ".asx");
1683
                else if (strcmp(eosf - 3, ".rm") == 0)
1684
                    strcpy(eosf - 3, ".ram");
1685
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1686
                    /* generate a sample RTSP director if
1687
                       unicast. Generate an SDP redirector if
1688
                       multicast */
1689
                    eosf = strrchr(sfilename, '.');
1690
                    if (!eosf)
1691
                        eosf = sfilename + strlen(sfilename);
1692
                    if (stream->is_multicast)
1693
                        strcpy(eosf, ".sdp");
1694
                    else
1695
                        strcpy(eosf, ".rtsp");
1696
                }
1697
            }
1698

    
1699
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1700
                         sfilename, stream->filename);
1701
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1702
                        stream->conns_served);
1703
            fmt_bytecount(pb, stream->bytes_served);
1704
            switch(stream->stream_type) {
1705
            case STREAM_TYPE_LIVE: {
1706
                    int audio_bit_rate = 0;
1707
                    int video_bit_rate = 0;
1708
                    const char *audio_codec_name = "";
1709
                    const char *video_codec_name = "";
1710
                    const char *audio_codec_name_extra = "";
1711
                    const char *video_codec_name_extra = "";
1712

    
1713
                    for(i=0;i<stream->nb_streams;i++) {
1714
                        AVStream *st = stream->streams[i];
1715
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1716
                        switch(st->codec->codec_type) {
1717
                        case CODEC_TYPE_AUDIO:
1718
                            audio_bit_rate += st->codec->bit_rate;
1719
                            if (codec) {
1720
                                if (*audio_codec_name)
1721
                                    audio_codec_name_extra = "...";
1722
                                audio_codec_name = codec->name;
1723
                            }
1724
                            break;
1725
                        case CODEC_TYPE_VIDEO:
1726
                            video_bit_rate += st->codec->bit_rate;
1727
                            if (codec) {
1728
                                if (*video_codec_name)
1729
                                    video_codec_name_extra = "...";
1730
                                video_codec_name = codec->name;
1731
                            }
1732
                            break;
1733
                        case CODEC_TYPE_DATA:
1734
                            video_bit_rate += st->codec->bit_rate;
1735
                            break;
1736
                        default:
1737
                            abort();
1738
                        }
1739
                    }
1740
                    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",
1741
                                 stream->fmt->name,
1742
                                 stream->bandwidth,
1743
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1744
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1745
                    if (stream->feed)
1746
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1747
                    else
1748
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1749
                    url_fprintf(pb, "\n");
1750
                }
1751
                break;
1752
            default:
1753
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1754
                break;
1755
            }
1756
        }
1757
        stream = stream->next;
1758
    }
1759
    url_fprintf(pb, "</TABLE>\n");
1760

    
1761
    stream = first_stream;
1762
    while (stream != NULL) {
1763
        if (stream->feed == stream) {
1764
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1765
            if (stream->pid) {
1766
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1767

    
1768
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1769
                {
1770
                    FILE *pid_stat;
1771
                    char ps_cmd[64];
1772

    
1773
                    /* This is somewhat linux specific I guess */
1774
                    snprintf(ps_cmd, sizeof(ps_cmd),
1775
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1776
                             stream->pid);
1777

    
1778
                    pid_stat = popen(ps_cmd, "r");
1779
                    if (pid_stat) {
1780
                        char cpuperc[10];
1781
                        char cpuused[64];
1782

    
1783
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1784
                                   cpuused) == 2) {
1785
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1786
                                         cpuperc, cpuused);
1787
                        }
1788
                        fclose(pid_stat);
1789
                    }
1790
                }
1791
#endif
1792

    
1793
                url_fprintf(pb, "<p>");
1794
            }
1795
            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");
1796

    
1797
            for (i = 0; i < stream->nb_streams; i++) {
1798
                AVStream *st = stream->streams[i];
1799
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1800
                const char *type = "unknown";
1801
                char parameters[64];
1802

    
1803
                parameters[0] = 0;
1804

    
1805
                switch(st->codec->codec_type) {
1806
                case CODEC_TYPE_AUDIO:
1807
                    type = "audio";
1808
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1809
                    break;
1810
                case CODEC_TYPE_VIDEO:
1811
                    type = "video";
1812
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1813
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1814
                    break;
1815
                default:
1816
                    abort();
1817
                }
1818
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1819
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1820
            }
1821
            url_fprintf(pb, "</table>\n");
1822

    
1823
        }
1824
        stream = stream->next;
1825
    }
1826

    
1827
#if 0
1828
    {
1829
        float avg;
1830
        AVCodecContext *enc;
1831
        char buf[1024];
1832

1833
        /* feed status */
1834
        stream = first_feed;
1835
        while (stream != NULL) {
1836
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1837
            url_fprintf(pb, "<TABLE>\n");
1838
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1839
            for(i=0;i<stream->nb_streams;i++) {
1840
                AVStream *st = stream->streams[i];
1841
                FeedData *fdata = st->priv_data;
1842
                enc = st->codec;
1843

1844
                avcodec_string(buf, sizeof(buf), enc);
1845
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1846
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1847
                    avg /= enc->frame_size;
1848
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1849
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1850
            }
1851
            url_fprintf(pb, "</TABLE>\n");
1852
            stream = stream->next_feed;
1853
        }
1854
    }
1855
#endif
1856

    
1857
    /* connection status */
1858
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1859

    
1860
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1861
                 nb_connections, nb_max_connections);
1862

    
1863
    url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
1864
                 current_bandwidth, max_bandwidth);
1865

    
1866
    url_fprintf(pb, "<TABLE>\n");
1867
    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");
1868
    c1 = first_http_ctx;
1869
    i = 0;
1870
    while (c1 != NULL) {
1871
        int bitrate;
1872
        int j;
1873

    
1874
        bitrate = 0;
1875
        if (c1->stream) {
1876
            for (j = 0; j < c1->stream->nb_streams; j++) {
1877
                if (!c1->stream->feed)
1878
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1879
                else if (c1->feed_streams[j] >= 0)
1880
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1881
            }
1882
        }
1883

    
1884
        i++;
1885
        p = inet_ntoa(c1->from_addr.sin_addr);
1886
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1887
                    i,
1888
                    c1->stream ? c1->stream->filename : "",
1889
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1890
                    p,
1891
                    c1->protocol,
1892
                    http_state[c1->state]);
1893
        fmt_bytecount(pb, bitrate);
1894
        url_fprintf(pb, "<td align=right>");
1895
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1896
        url_fprintf(pb, "<td align=right>");
1897
        fmt_bytecount(pb, c1->data_count);
1898
        url_fprintf(pb, "\n");
1899
        c1 = c1->next;
1900
    }
1901
    url_fprintf(pb, "</TABLE>\n");
1902

    
1903
    /* date */
1904
    ti = time(NULL);
1905
    p = ctime(&ti);
1906
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1907
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1908

    
1909
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1910
    c->buffer_ptr = c->pb_buffer;
1911
    c->buffer_end = c->pb_buffer + len;
1912
}
1913

    
1914
/* check if the parser needs to be opened for stream i */
1915
static void open_parser(AVFormatContext *s, int i)
1916
{
1917
    AVStream *st = s->streams[i];
1918
    AVCodec *codec;
1919

    
1920
    if (!st->codec->codec) {
1921
        codec = avcodec_find_decoder(st->codec->codec_id);
1922
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1923
            st->codec->parse_only = 1;
1924
            if (avcodec_open(st->codec, codec) < 0)
1925
                st->codec->parse_only = 0;
1926
        }
1927
    }
1928
}
1929

    
1930
static int open_input_stream(HTTPContext *c, const char *info)
1931
{
1932
    char buf[128];
1933
    char input_filename[1024];
1934
    AVFormatContext *s;
1935
    int buf_size, i, ret;
1936
    int64_t stream_pos;
1937

    
1938
    /* find file name */
1939
    if (c->stream->feed) {
1940
        strcpy(input_filename, c->stream->feed->feed_filename);
1941
        buf_size = FFM_PACKET_SIZE;
1942
        /* compute position (absolute time) */
1943
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1944
            stream_pos = parse_date(buf, 0);
1945
            if (stream_pos == INT64_MIN)
1946
                return -1;
1947
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1948
            int prebuffer = strtol(buf, 0, 10);
1949
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1950
        } else
1951
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1952
    } else {
1953
        strcpy(input_filename, c->stream->feed_filename);
1954
        buf_size = 0;
1955
        /* compute position (relative time) */
1956
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1957
            stream_pos = parse_date(buf, 1);
1958
            if (stream_pos == INT64_MIN)
1959
                return -1;
1960
        } else
1961
            stream_pos = 0;
1962
    }
1963
    if (input_filename[0] == '\0')
1964
        return -1;
1965

    
1966
#if 0
1967
    { time_t when = stream_pos / 1000000;
1968
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1969
    }
1970
#endif
1971

    
1972
    /* open stream */
1973
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1974
                                  buf_size, c->stream->ap_in)) < 0) {
1975
        http_log("could not open %s: %d\n", input_filename, ret);
1976
        return -1;
1977
    }
1978
    s->flags |= AVFMT_FLAG_GENPTS;
1979
    c->fmt_in = s;
1980
    av_find_stream_info(c->fmt_in);
1981

    
1982
    /* open each parser */
1983
    for(i=0;i<s->nb_streams;i++)
1984
        open_parser(s, i);
1985

    
1986
    /* choose stream as clock source (we favorize video stream if
1987
       present) for packet sending */
1988
    c->pts_stream_index = 0;
1989
    for(i=0;i<c->stream->nb_streams;i++) {
1990
        if (c->pts_stream_index == 0 &&
1991
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1992
            c->pts_stream_index = i;
1993
        }
1994
    }
1995

    
1996
#if 1
1997
    if (c->fmt_in->iformat->read_seek)
1998
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1999
#endif
2000
    /* set the start time (needed for maxtime and RTP packet timing) */
2001
    c->start_time = cur_time;
2002
    c->first_pts = AV_NOPTS_VALUE;
2003
    return 0;
2004
}
2005

    
2006
/* return the server clock (in us) */
2007
static int64_t get_server_clock(HTTPContext *c)
2008
{
2009
    /* compute current pts value from system time */
2010
    return (cur_time - c->start_time) * 1000;
2011
}
2012

    
2013
/* return the estimated time at which the current packet must be sent
2014
   (in us) */
2015
static int64_t get_packet_send_clock(HTTPContext *c)
2016
{
2017
    int bytes_left, bytes_sent, frame_bytes;
2018

    
2019
    frame_bytes = c->cur_frame_bytes;
2020
    if (frame_bytes <= 0)
2021
        return c->cur_pts;
2022
    else {
2023
        bytes_left = c->buffer_end - c->buffer_ptr;
2024
        bytes_sent = frame_bytes - bytes_left;
2025
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2026
    }
2027
}
2028

    
2029

    
2030
static int http_prepare_data(HTTPContext *c)
2031
{
2032
    int i, len, ret;
2033
    AVFormatContext *ctx;
2034

    
2035
    av_freep(&c->pb_buffer);
2036
    switch(c->state) {
2037
    case HTTPSTATE_SEND_DATA_HEADER:
2038
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2039
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
2040
                   sizeof(c->fmt_ctx.author));
2041
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2042
                   sizeof(c->fmt_ctx.comment));
2043
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2044
                   sizeof(c->fmt_ctx.copyright));
2045
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2046
                   sizeof(c->fmt_ctx.title));
2047

    
2048
        for(i=0;i<c->stream->nb_streams;i++) {
2049
            AVStream *st;
2050
            AVStream *src;
2051
            st = av_mallocz(sizeof(AVStream));
2052
            c->fmt_ctx.streams[i] = st;
2053
            /* if file or feed, then just take streams from FFStream struct */
2054
            if (!c->stream->feed ||
2055
                c->stream->feed == c->stream)
2056
                src = c->stream->streams[i];
2057
            else
2058
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2059

    
2060
            *st = *src;
2061
            st->priv_data = 0;
2062
            st->codec->frame_number = 0; /* XXX: should be done in
2063
                                           AVStream, not in codec */
2064
        }
2065
        /* set output format parameters */
2066
        c->fmt_ctx.oformat = c->stream->fmt;
2067
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2068

    
2069
        c->got_key_frame = 0;
2070

    
2071
        /* prepare header and save header data in a stream */
2072
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2073
            /* XXX: potential leak */
2074
            return -1;
2075
        }
2076
        c->fmt_ctx.pb->is_streamed = 1;
2077

    
2078
        /*
2079
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2080
         * Default value from FFmpeg
2081
         * Try to set it use configuration option
2082
         */
2083
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2084
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2085

    
2086
        av_set_parameters(&c->fmt_ctx, NULL);
2087
        if (av_write_header(&c->fmt_ctx) < 0) {
2088
            http_log("Error writing output header\n");
2089
            return -1;
2090
        }
2091

    
2092
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2093
        c->buffer_ptr = c->pb_buffer;
2094
        c->buffer_end = c->pb_buffer + len;
2095

    
2096
        c->state = HTTPSTATE_SEND_DATA;
2097
        c->last_packet_sent = 0;
2098
        break;
2099
    case HTTPSTATE_SEND_DATA:
2100
        /* find a new packet */
2101
        /* read a packet from the input stream */
2102
        if (c->stream->feed)
2103
            ffm_set_write_index(c->fmt_in,
2104
                                c->stream->feed->feed_write_index,
2105
                                c->stream->feed->feed_size);
2106

    
2107
        if (c->stream->max_time &&
2108
            c->stream->max_time + c->start_time - cur_time < 0)
2109
            /* We have timed out */
2110
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2111
        else {
2112
            AVPacket pkt;
2113
        redo:
2114
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2115
                if (c->stream->feed && c->stream->feed->feed_opened) {
2116
                    /* if coming from feed, it means we reached the end of the
2117
                       ffm file, so must wait for more data */
2118
                    c->state = HTTPSTATE_WAIT_FEED;
2119
                    return 1; /* state changed */
2120
                } else {
2121
                    if (c->stream->loop) {
2122
                        av_close_input_file(c->fmt_in);
2123
                        c->fmt_in = NULL;
2124
                        if (open_input_stream(c, "") < 0)
2125
                            goto no_loop;
2126
                        goto redo;
2127
                    } else {
2128
                    no_loop:
2129
                        /* must send trailer now because eof or error */
2130
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2131
                    }
2132
                }
2133
            } else {
2134
                int source_index = pkt.stream_index;
2135
                /* update first pts if needed */
2136
                if (c->first_pts == AV_NOPTS_VALUE) {
2137
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2138
                    c->start_time = cur_time;
2139
                }
2140
                /* send it to the appropriate stream */
2141
                if (c->stream->feed) {
2142
                    /* if coming from a feed, select the right stream */
2143
                    if (c->switch_pending) {
2144
                        c->switch_pending = 0;
2145
                        for(i=0;i<c->stream->nb_streams;i++) {
2146
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2147
                                if (pkt.flags & PKT_FLAG_KEY)
2148
                                    do_switch_stream(c, i);
2149
                            if (c->switch_feed_streams[i] >= 0)
2150
                                c->switch_pending = 1;
2151
                        }
2152
                    }
2153
                    for(i=0;i<c->stream->nb_streams;i++) {
2154
                        if (c->feed_streams[i] == pkt.stream_index) {
2155
                            AVStream *st = c->fmt_in->streams[source_index];
2156
                            pkt.stream_index = i;
2157
                            if (pkt.flags & PKT_FLAG_KEY &&
2158
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2159
                                 c->stream->nb_streams == 1))
2160
                                c->got_key_frame = 1;
2161
                            if (!c->stream->send_on_key || c->got_key_frame)
2162
                                goto send_it;
2163
                        }
2164
                    }
2165
                } else {
2166
                    AVCodecContext *codec;
2167
                    AVStream *ist, *ost;
2168
                send_it:
2169
                    ist = c->fmt_in->streams[source_index];
2170
                    /* specific handling for RTP: we use several
2171
                       output stream (one for each RTP
2172
                       connection). XXX: need more abstract handling */
2173
                    if (c->is_packetized) {
2174
                        /* compute send time and duration */
2175
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2176
                        if (ist->start_time != AV_NOPTS_VALUE)
2177
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2178
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2179
#if 0
2180
                        printf("index=%d pts=%0.3f duration=%0.6f\n",
2181
                               pkt.stream_index,
2182
                               (double)c->cur_pts /
2183
                               AV_TIME_BASE,
2184
                               (double)c->cur_frame_duration /
2185
                               AV_TIME_BASE);
2186
#endif
2187
                        /* find RTP context */
2188
                        c->packet_stream_index = pkt.stream_index;
2189
                        ctx = c->rtp_ctx[c->packet_stream_index];
2190
                        if(!ctx) {
2191
                            av_free_packet(&pkt);
2192
                            break;
2193
                        }
2194
                        codec = ctx->streams[0]->codec;
2195
                        /* only one stream per RTP connection */
2196
                        pkt.stream_index = 0;
2197
                    } else {
2198
                        ctx = &c->fmt_ctx;
2199
                        /* Fudge here */
2200
                        codec = ctx->streams[pkt.stream_index]->codec;
2201
                    }
2202

    
2203
                    if (c->is_packetized) {
2204
                        int max_packet_size;
2205
                        if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2206
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2207
                        else
2208
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2209
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2210
                    } else {
2211
                        ret = url_open_dyn_buf(&ctx->pb);
2212
                    }
2213
                    if (ret < 0) {
2214
                        /* XXX: potential leak */
2215
                        return -1;
2216
                    }
2217
                    ost = ctx->streams[pkt.stream_index];
2218

    
2219
                    ctx->pb->is_streamed = 1;
2220
                    if (pkt.dts != AV_NOPTS_VALUE)
2221
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2222
                    if (pkt.pts != AV_NOPTS_VALUE)
2223
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2224
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2225
                    if (av_write_frame(ctx, &pkt) < 0) {
2226
                        http_log("Error writing frame to output\n");
2227
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2228
                    }
2229

    
2230
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2231
                    c->cur_frame_bytes = len;
2232
                    c->buffer_ptr = c->pb_buffer;
2233
                    c->buffer_end = c->pb_buffer + len;
2234

    
2235
                    codec->frame_number++;
2236
                    if (len == 0) {
2237
                        av_free_packet(&pkt);
2238
                        goto redo;
2239
                    }
2240
                }
2241
                av_free_packet(&pkt);
2242
            }
2243
        }
2244
        break;
2245
    default:
2246
    case HTTPSTATE_SEND_DATA_TRAILER:
2247
        /* last packet test ? */
2248
        if (c->last_packet_sent || c->is_packetized)
2249
            return -1;
2250
        ctx = &c->fmt_ctx;
2251
        /* prepare header */
2252
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2253
            /* XXX: potential leak */
2254
            return -1;
2255
        }
2256
        c->fmt_ctx.pb->is_streamed = 1;
2257
        av_write_trailer(ctx);
2258
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2259
        c->buffer_ptr = c->pb_buffer;
2260
        c->buffer_end = c->pb_buffer + len;
2261

    
2262
        c->last_packet_sent = 1;
2263
        break;
2264
    }
2265
    return 0;
2266
}
2267

    
2268
/* should convert the format at the same time */
2269
/* send data starting at c->buffer_ptr to the output connection
2270
   (either UDP or TCP connection) */
2271
static int http_send_data(HTTPContext *c)
2272
{
2273
    int len, ret;
2274

    
2275
    for(;;) {
2276
        if (c->buffer_ptr >= c->buffer_end) {
2277
            ret = http_prepare_data(c);
2278
            if (ret < 0)
2279
                return -1;
2280
            else if (ret != 0)
2281
                /* state change requested */
2282
                break;
2283
        } else {
2284
            if (c->is_packetized) {
2285
                /* RTP data output */
2286
                len = c->buffer_end - c->buffer_ptr;
2287
                if (len < 4) {
2288
                    /* fail safe - should never happen */
2289
                fail1:
2290
                    c->buffer_ptr = c->buffer_end;
2291
                    return 0;
2292
                }
2293
                len = (c->buffer_ptr[0] << 24) |
2294
                    (c->buffer_ptr[1] << 16) |
2295
                    (c->buffer_ptr[2] << 8) |
2296
                    (c->buffer_ptr[3]);
2297
                if (len > (c->buffer_end - c->buffer_ptr))
2298
                    goto fail1;
2299
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2300
                    /* nothing to send yet: we can wait */
2301
                    return 0;
2302
                }
2303

    
2304
                c->data_count += len;
2305
                update_datarate(&c->datarate, c->data_count);
2306
                if (c->stream)
2307
                    c->stream->bytes_served += len;
2308

    
2309
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2310
                    /* RTP packets are sent inside the RTSP TCP connection */
2311
                    ByteIOContext *pb;
2312
                    int interleaved_index, size;
2313
                    uint8_t header[4];
2314
                    HTTPContext *rtsp_c;
2315

    
2316
                    rtsp_c = c->rtsp_c;
2317
                    /* if no RTSP connection left, error */
2318
                    if (!rtsp_c)
2319
                        return -1;
2320
                    /* if already sending something, then wait. */
2321
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2322
                        break;
2323
                    if (url_open_dyn_buf(&pb) < 0)
2324
                        goto fail1;
2325
                    interleaved_index = c->packet_stream_index * 2;
2326
                    /* RTCP packets are sent at odd indexes */
2327
                    if (c->buffer_ptr[1] == 200)
2328
                        interleaved_index++;
2329
                    /* write RTSP TCP header */
2330
                    header[0] = '$';
2331
                    header[1] = interleaved_index;
2332
                    header[2] = len >> 8;
2333
                    header[3] = len;
2334
                    put_buffer(pb, header, 4);
2335
                    /* write RTP packet data */
2336
                    c->buffer_ptr += 4;
2337
                    put_buffer(pb, c->buffer_ptr, len);
2338
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2339
                    /* prepare asynchronous TCP sending */
2340
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2341
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2342
                    c->buffer_ptr += len;
2343

    
2344
                    /* send everything we can NOW */
2345
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2346
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2347
                    if (len > 0)
2348
                        rtsp_c->packet_buffer_ptr += len;
2349
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2350
                        /* if we could not send all the data, we will
2351
                           send it later, so a new state is needed to
2352
                           "lock" the RTSP TCP connection */
2353
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2354
                        break;
2355
                    } else
2356
                        /* all data has been sent */
2357
                        av_freep(&c->packet_buffer);
2358
                } else {
2359
                    /* send RTP packet directly in UDP */
2360
                    c->buffer_ptr += 4;
2361
                    url_write(c->rtp_handles[c->packet_stream_index],
2362
                              c->buffer_ptr, len);
2363
                    c->buffer_ptr += len;
2364
                    /* here we continue as we can send several packets per 10 ms slot */
2365
                }
2366
            } else {
2367
                /* TCP data output */
2368
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2369
                if (len < 0) {
2370
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2371
                        ff_neterrno() != FF_NETERROR(EINTR))
2372
                        /* error : close connection */
2373
                        return -1;
2374
                    else
2375
                        return 0;
2376
                } else
2377
                    c->buffer_ptr += len;
2378

    
2379
                c->data_count += len;
2380
                update_datarate(&c->datarate, c->data_count);
2381
                if (c->stream)
2382
                    c->stream->bytes_served += len;
2383
                break;
2384
            }
2385
        }
2386
    } /* for(;;) */
2387
    return 0;
2388
}
2389

    
2390
static int http_start_receive_data(HTTPContext *c)
2391
{
2392
    int fd;
2393

    
2394
    if (c->stream->feed_opened)
2395
        return -1;
2396

    
2397
    /* Don't permit writing to this one */
2398
    if (c->stream->readonly)
2399
        return -1;
2400

    
2401
    /* open feed */
2402
    fd = open(c->stream->feed_filename, O_RDWR);
2403
    if (fd < 0) {
2404
        http_log("Error opening feeder file: %s\n", strerror(errno));
2405
        return -1;
2406
    }
2407
    c->feed_fd = fd;
2408

    
2409
    c->stream->feed_write_index = ffm_read_write_index(fd);
2410
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2411
    lseek(fd, 0, SEEK_SET);
2412

    
2413
    /* init buffer input */
2414
    c->buffer_ptr = c->buffer;
2415
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2416
    c->stream->feed_opened = 1;
2417
    return 0;
2418
}
2419

    
2420
static int http_receive_data(HTTPContext *c)
2421
{
2422
    HTTPContext *c1;
2423

    
2424
    if (c->buffer_end > c->buffer_ptr) {
2425
        int len;
2426

    
2427
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2428
        if (len < 0) {
2429
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2430
                ff_neterrno() != FF_NETERROR(EINTR))
2431
                /* error : close connection */
2432
                goto fail;
2433
        } else if (len == 0)
2434
            /* end of connection : close it */
2435
            goto fail;
2436
        else {
2437
            c->buffer_ptr += len;
2438
            c->data_count += len;
2439
            update_datarate(&c->datarate, c->data_count);
2440
        }
2441
    }
2442

    
2443
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2444
        if (c->buffer[0] != 'f' ||
2445
            c->buffer[1] != 'm') {
2446
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2447
            goto fail;
2448
        }
2449
    }
2450

    
2451
    if (c->buffer_ptr >= c->buffer_end) {
2452
        FFStream *feed = c->stream;
2453
        /* a packet has been received : write it in the store, except
2454
           if header */
2455
        if (c->data_count > FFM_PACKET_SIZE) {
2456

    
2457
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2458
            /* XXX: use llseek or url_seek */
2459
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2460
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2461
                http_log("Error writing to feed file: %s\n", strerror(errno));
2462
                goto fail;
2463
            }
2464

    
2465
            feed->feed_write_index += FFM_PACKET_SIZE;
2466
            /* update file size */
2467
            if (feed->feed_write_index > c->stream->feed_size)
2468
                feed->feed_size = feed->feed_write_index;
2469

    
2470
            /* handle wrap around if max file size reached */
2471
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2472
                feed->feed_write_index = FFM_PACKET_SIZE;
2473

    
2474
            /* write index */
2475
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2476

    
2477
            /* wake up any waiting connections */
2478
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2479
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2480
                    c1->stream->feed == c->stream->feed)
2481
                    c1->state = HTTPSTATE_SEND_DATA;
2482
            }
2483
        } else {
2484
            /* We have a header in our hands that contains useful data */
2485
            AVFormatContext *s = NULL;
2486
            ByteIOContext *pb;
2487
            AVInputFormat *fmt_in;
2488
            int i;
2489

    
2490
            /* use feed output format name to find corresponding input format */
2491
            fmt_in = av_find_input_format(feed->fmt->name);
2492
            if (!fmt_in)
2493
                goto fail;
2494

    
2495
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2496
            pb->is_streamed = 1;
2497

    
2498
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2499
                av_free(pb);
2500
                goto fail;
2501
            }
2502

    
2503
            /* Now we have the actual streams */
2504
            if (s->nb_streams != feed->nb_streams) {
2505
                av_close_input_stream(s);
2506
                av_free(pb);
2507
                goto fail;
2508
            }
2509

    
2510
            for (i = 0; i < s->nb_streams; i++) {
2511
                AVStream *fst = feed->streams[i];
2512
                AVStream *st = s->streams[i];
2513
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2514
                if (fst->codec->extradata_size) {
2515
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2516
                    if (!fst->codec->extradata)
2517
                        goto fail;
2518
                    memcpy(fst->codec->extradata, st->codec->extradata,
2519
                           fst->codec->extradata_size);
2520
                }
2521
            }
2522

    
2523
            av_close_input_stream(s);
2524
            av_free(pb);
2525
        }
2526
        c->buffer_ptr = c->buffer;
2527
    }
2528

    
2529
    return 0;
2530
 fail:
2531
    c->stream->feed_opened = 0;
2532
    close(c->feed_fd);
2533
    /* wake up any waiting connections to stop waiting for feed */
2534
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2535
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2536
            c1->stream->feed == c->stream->feed)
2537
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2538
    }
2539
    return -1;
2540
}
2541

    
2542
/********************************************************************/
2543
/* RTSP handling */
2544

    
2545
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2546
{
2547
    const char *str;
2548
    time_t ti;
2549
    char *p;
2550
    char buf2[32];
2551

    
2552
    switch(error_number) {
2553
    case RTSP_STATUS_OK:
2554
        str = "OK";
2555
        break;
2556
    case RTSP_STATUS_METHOD:
2557
        str = "Method Not Allowed";
2558
        break;
2559
    case RTSP_STATUS_BANDWIDTH:
2560
        str = "Not Enough Bandwidth";
2561
        break;
2562
    case RTSP_STATUS_SESSION:
2563
        str = "Session Not Found";
2564
        break;
2565
    case RTSP_STATUS_STATE:
2566
        str = "Method Not Valid in This State";
2567
        break;
2568
    case RTSP_STATUS_AGGREGATE:
2569
        str = "Aggregate operation not allowed";
2570
        break;
2571
    case RTSP_STATUS_ONLY_AGGREGATE:
2572
        str = "Only aggregate operation allowed";
2573
        break;
2574
    case RTSP_STATUS_TRANSPORT:
2575
        str = "Unsupported transport";
2576
        break;
2577
    case RTSP_STATUS_INTERNAL:
2578
        str = "Internal Server Error";
2579
        break;
2580
    case RTSP_STATUS_SERVICE:
2581
        str = "Service Unavailable";
2582
        break;
2583
    case RTSP_STATUS_VERSION:
2584
        str = "RTSP Version not supported";
2585
        break;
2586
    default:
2587
        str = "Unknown Error";
2588
        break;
2589
    }
2590

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

    
2594
    /* output GMT time */
2595
    ti = time(NULL);
2596
    p = ctime(&ti);
2597
    strcpy(buf2, p);
2598
    p = buf2 + strlen(p) - 1;
2599
    if (*p == '\n')
2600
        *p = '\0';
2601
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2602
}
2603

    
2604
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2605
{
2606
    rtsp_reply_header(c, error_number);
2607
    url_fprintf(c->pb, "\r\n");
2608
}
2609

    
2610
static int rtsp_parse_request(HTTPContext *c)
2611
{
2612
    const char *p, *p1, *p2;
2613
    char cmd[32];
2614
    char url[1024];
2615
    char protocol[32];
2616
    char line[1024];
2617
    int len;
2618
    RTSPHeader header1, *header = &header1;
2619

    
2620
    c->buffer_ptr[0] = '\0';
2621
    p = c->buffer;
2622

    
2623
    get_word(cmd, sizeof(cmd), &p);
2624
    get_word(url, sizeof(url), &p);
2625
    get_word(protocol, sizeof(protocol), &p);
2626

    
2627
    av_strlcpy(c->method, cmd, sizeof(c->method));
2628
    av_strlcpy(c->url, url, sizeof(c->url));
2629
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2630

    
2631
    if (url_open_dyn_buf(&c->pb) < 0) {
2632
        /* XXX: cannot do more */
2633
        c->pb = NULL; /* safety */
2634
        return -1;
2635
    }
2636

    
2637
    /* check version name */
2638
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2639
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2640
        goto the_end;
2641
    }
2642

    
2643
    /* parse each header line */
2644
    memset(header, 0, sizeof(RTSPHeader));
2645
    /* skip to next line */
2646
    while (*p != '\n' && *p != '\0')
2647
        p++;
2648
    if (*p == '\n')
2649
        p++;
2650
    while (*p != '\0') {
2651
        p1 = strchr(p, '\n');
2652
        if (!p1)
2653
            break;
2654
        p2 = p1;
2655
        if (p2 > p && p2[-1] == '\r')
2656
            p2--;
2657
        /* skip empty line */
2658
        if (p2 == p)
2659
            break;
2660
        len = p2 - p;
2661
        if (len > sizeof(line) - 1)
2662
            len = sizeof(line) - 1;
2663
        memcpy(line, p, len);
2664
        line[len] = '\0';
2665
        rtsp_parse_line(header, line);
2666
        p = p1 + 1;
2667
    }
2668

    
2669
    /* handle sequence number */
2670
    c->seq = header->seq;
2671

    
2672
    if (!strcmp(cmd, "DESCRIBE"))
2673
        rtsp_cmd_describe(c, url);
2674
    else if (!strcmp(cmd, "OPTIONS"))
2675
        rtsp_cmd_options(c, url);
2676
    else if (!strcmp(cmd, "SETUP"))
2677
        rtsp_cmd_setup(c, url, header);
2678
    else if (!strcmp(cmd, "PLAY"))
2679
        rtsp_cmd_play(c, url, header);
2680
    else if (!strcmp(cmd, "PAUSE"))
2681
        rtsp_cmd_pause(c, url, header);
2682
    else if (!strcmp(cmd, "TEARDOWN"))
2683
        rtsp_cmd_teardown(c, url, header);
2684
    else
2685
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2686

    
2687
 the_end:
2688
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2689
    c->pb = NULL; /* safety */
2690
    if (len < 0) {
2691
        /* XXX: cannot do more */
2692
        return -1;
2693
    }
2694
    c->buffer_ptr = c->pb_buffer;
2695
    c->buffer_end = c->pb_buffer + len;
2696
    c->state = RTSPSTATE_SEND_REPLY;
2697
    return 0;
2698
}
2699

    
2700
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2701
                                   struct in_addr my_ip)
2702
{
2703
    AVFormatContext *avc;
2704
    AVStream avs[MAX_STREAMS];
2705
    int i;
2706

    
2707
    avc =  av_alloc_format_context();
2708
    if (avc == NULL) {
2709
        return -1;
2710
    }
2711
    if (stream->title[0] != 0) {
2712
        av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2713
    } else {
2714
        av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2715
    }
2716
    avc->nb_streams = stream->nb_streams;
2717
    if (stream->is_multicast) {
2718
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2719
                 inet_ntoa(stream->multicast_ip),
2720
                 stream->multicast_port, stream->multicast_ttl);
2721
    }
2722

    
2723
    for(i = 0; i < stream->nb_streams; i++) {
2724
        avc->streams[i] = &avs[i];
2725
        avc->streams[i]->codec = stream->streams[i]->codec;
2726
    }
2727
    *pbuffer = av_mallocz(2048);
2728
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2729
    av_free(avc);
2730

    
2731
    return strlen(*pbuffer);
2732
}
2733

    
2734
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2735
{
2736
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2737
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2738
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2739
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2740
    url_fprintf(c->pb, "\r\n");
2741
}
2742

    
2743
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2744
{
2745
    FFStream *stream;
2746
    char path1[1024];
2747
    const char *path;
2748
    uint8_t *content;
2749
    int content_length, len;
2750
    struct sockaddr_in my_addr;
2751

    
2752
    /* find which url is asked */
2753
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2754
    path = path1;
2755
    if (*path == '/')
2756
        path++;
2757

    
2758
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2759
        if (!stream->is_feed &&
2760
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2761
            !strcmp(path, stream->filename)) {
2762
            goto found;
2763
        }
2764
    }
2765
    /* no stream found */
2766
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2767
    return;
2768

    
2769
 found:
2770
    /* prepare the media description in sdp format */
2771

    
2772
    /* get the host IP */
2773
    len = sizeof(my_addr);
2774
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2775
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2776
    if (content_length < 0) {
2777
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2778
        return;
2779
    }
2780
    rtsp_reply_header(c, RTSP_STATUS_OK);
2781
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2782
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2783
    url_fprintf(c->pb, "\r\n");
2784
    put_buffer(c->pb, content, content_length);
2785
}
2786

    
2787
static HTTPContext *find_rtp_session(const char *session_id)
2788
{
2789
    HTTPContext *c;
2790

    
2791
    if (session_id[0] == '\0')
2792
        return NULL;
2793

    
2794
    for(c = first_http_ctx; c != NULL; c = c->next) {
2795
        if (!strcmp(c->session_id, session_id))
2796
            return c;
2797
    }
2798
    return NULL;
2799
}
2800

    
2801
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2802
{
2803
    RTSPTransportField *th;
2804
    int i;
2805

    
2806
    for(i=0;i<h->nb_transports;i++) {
2807
        th = &h->transports[i];
2808
        if (th->protocol == protocol)
2809
            return th;
2810
    }
2811
    return NULL;
2812
}
2813

    
2814
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2815
                           RTSPHeader *h)
2816
{
2817
    FFStream *stream;
2818
    int stream_index, port;
2819
    char buf[1024];
2820
    char path1[1024];
2821
    const char *path;
2822
    HTTPContext *rtp_c;
2823
    RTSPTransportField *th;
2824
    struct sockaddr_in dest_addr;
2825
    RTSPActionServerSetup setup;
2826

    
2827
    /* find which url is asked */
2828
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2829
    path = path1;
2830
    if (*path == '/')
2831
        path++;
2832

    
2833
    /* now check each stream */
2834
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2835
        if (!stream->is_feed &&
2836
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2837
            /* accept aggregate filenames only if single stream */
2838
            if (!strcmp(path, stream->filename)) {
2839
                if (stream->nb_streams != 1) {
2840
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2841
                    return;
2842
                }
2843
                stream_index = 0;
2844
                goto found;
2845
            }
2846

    
2847
            for(stream_index = 0; stream_index < stream->nb_streams;
2848
                stream_index++) {
2849
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2850
                         stream->filename, stream_index);
2851
                if (!strcmp(path, buf))
2852
                    goto found;
2853
            }
2854
        }
2855
    }
2856
    /* no stream found */
2857
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2858
    return;
2859
 found:
2860

    
2861
    /* generate session id if needed */
2862
    if (h->session_id[0] == '\0')
2863
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2864
                 av_random(&random_state), av_random(&random_state));
2865

    
2866
    /* find rtp session, and create it if none found */
2867
    rtp_c = find_rtp_session(h->session_id);
2868
    if (!rtp_c) {
2869
        /* always prefer UDP */
2870
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2871
        if (!th) {
2872
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2873
            if (!th) {
2874
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2875
                return;
2876
            }
2877
        }
2878

    
2879
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2880
                                   th->protocol);
2881
        if (!rtp_c) {
2882
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2883
            return;
2884
        }
2885

    
2886
        /* open input stream */
2887
        if (open_input_stream(rtp_c, "") < 0) {
2888
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2889
            return;
2890
        }
2891
    }
2892

    
2893
    /* test if stream is OK (test needed because several SETUP needs
2894
       to be done for a given file) */
2895
    if (rtp_c->stream != stream) {
2896
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2897
        return;
2898
    }
2899

    
2900
    /* test if stream is already set up */
2901
    if (rtp_c->rtp_ctx[stream_index]) {
2902
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2903
        return;
2904
    }
2905

    
2906
    /* check transport */
2907
    th = find_transport(h, rtp_c->rtp_protocol);
2908
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2909
                th->client_port_min <= 0)) {
2910
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2911
        return;
2912
    }
2913

    
2914
    /* setup default options */
2915
    setup.transport_option[0] = '\0';
2916
    dest_addr = rtp_c->from_addr;
2917
    dest_addr.sin_port = htons(th->client_port_min);
2918

    
2919
    /* setup stream */
2920
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2921
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2922
        return;
2923
    }
2924

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

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

    
2949

    
2950
    url_fprintf(c->pb, "\r\n");
2951
}
2952

    
2953

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

    
2965
    rtp_c = find_rtp_session(session_id);
2966
    if (!rtp_c)
2967
        return NULL;
2968

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

    
2986
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2987
{
2988
    HTTPContext *rtp_c;
2989

    
2990
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2991
    if (!rtp_c) {
2992
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2993
        return;
2994
    }
2995

    
2996
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2997
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2998
        rtp_c->state != HTTPSTATE_READY) {
2999
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3000
        return;
3001
    }
3002

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

    
3011
    rtp_c->state = HTTPSTATE_SEND_DATA;
3012

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

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

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

    
3030
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3031
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3032
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3033
        return;
3034
    }
3035

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

    
3045
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3046
{
3047
    HTTPContext *rtp_c;
3048
    char session_id[32];
3049

    
3050
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3051
    if (!rtp_c) {
3052
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3053
        return;
3054
    }
3055

    
3056
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3057

    
3058
    /* abort the session */
3059
    close_connection(rtp_c);
3060

    
3061
    /* now everything is OK, so we can send the connection parameters */
3062
    rtsp_reply_header(c, RTSP_STATUS_OK);
3063
    /* session ID */
3064
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3065
    url_fprintf(c->pb, "\r\n");
3066
}
3067

    
3068

    
3069
/********************************************************************/
3070
/* RTP handling */
3071

    
3072
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3073
                                       FFStream *stream, const char *session_id,
3074
                                       enum RTSPProtocol rtp_protocol)
3075
{
3076
    HTTPContext *c = NULL;
3077
    const char *proto_str;
3078

    
3079
    /* XXX: should output a warning page when coming
3080
       close to the connection limit */
3081
    if (nb_connections >= nb_max_connections)
3082
        goto fail;
3083

    
3084
    /* add a new connection */
3085
    c = av_mallocz(sizeof(HTTPContext));
3086
    if (!c)
3087
        goto fail;
3088

    
3089
    c->fd = -1;
3090
    c->poll_entry = NULL;
3091
    c->from_addr = *from_addr;
3092
    c->buffer_size = IOBUFFER_INIT_SIZE;
3093
    c->buffer = av_malloc(c->buffer_size);
3094
    if (!c->buffer)
3095
        goto fail;
3096
    nb_connections++;
3097
    c->stream = stream;
3098
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3099
    c->state = HTTPSTATE_READY;
3100
    c->is_packetized = 1;
3101
    c->rtp_protocol = rtp_protocol;
3102

    
3103
    /* protocol is shown in statistics */
3104
    switch(c->rtp_protocol) {
3105
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3106
        proto_str = "MCAST";
3107
        break;
3108
    case RTSP_PROTOCOL_RTP_UDP:
3109
        proto_str = "UDP";
3110
        break;
3111
    case RTSP_PROTOCOL_RTP_TCP:
3112
        proto_str = "TCP";
3113
        break;
3114
    default:
3115
        proto_str = "???";
3116
        break;
3117
    }
3118
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3119
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3120

    
3121
    current_bandwidth += stream->bandwidth;
3122

    
3123
    c->next = first_http_ctx;
3124
    first_http_ctx = c;
3125
    return c;
3126

    
3127
 fail:
3128
    if (c) {
3129
        av_free(c->buffer);
3130
        av_free(c);
3131
    }
3132
    return NULL;
3133
}
3134

    
3135
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3136
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3137
   used. */
3138
static int rtp_new_av_stream(HTTPContext *c,
3139
                             int stream_index, struct sockaddr_in *dest_addr,
3140
                             HTTPContext *rtsp_c)
3141
{
3142
    AVFormatContext *ctx;
3143
    AVStream *st;
3144
    char *ipaddr;
3145
    URLContext *h = NULL;
3146
    uint8_t *dummy_buf;
3147
    int max_packet_size;
3148

    
3149
    /* now we can open the relevant output stream */
3150
    ctx = av_alloc_format_context();
3151
    if (!ctx)
3152
        return -1;
3153
    ctx->oformat = guess_format("rtp", NULL, NULL);
3154

    
3155
    st = av_mallocz(sizeof(AVStream));
3156
    if (!st)
3157
        goto fail;
3158
    st->codec= avcodec_alloc_context();
3159
    ctx->nb_streams = 1;
3160
    ctx->streams[0] = st;
3161

    
3162
    if (!c->stream->feed ||
3163
        c->stream->feed == c->stream)
3164
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3165
    else
3166
        memcpy(st,
3167
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3168
               sizeof(AVStream));
3169
    st->priv_data = NULL;
3170

    
3171
    /* build destination RTP address */
3172
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3173

    
3174
    switch(c->rtp_protocol) {
3175
    case RTSP_PROTOCOL_RTP_UDP:
3176
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3177
        /* RTP/UDP case */
3178

    
3179
        /* XXX: also pass as parameter to function ? */
3180
        if (c->stream->is_multicast) {
3181
            int ttl;
3182
            ttl = c->stream->multicast_ttl;
3183
            if (!ttl)
3184
                ttl = 16;
3185
            snprintf(ctx->filename, sizeof(ctx->filename),
3186
                     "rtp://%s:%d?multicast=1&ttl=%d",
3187
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3188
        } else {
3189
            snprintf(ctx->filename, sizeof(ctx->filename),
3190
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3191
        }
3192

    
3193
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3194
            goto fail;
3195
        c->rtp_handles[stream_index] = h;
3196
        max_packet_size = url_get_max_packet_size(h);
3197
        break;
3198
    case RTSP_PROTOCOL_RTP_TCP:
3199
        /* RTP/TCP case */
3200
        c->rtsp_c = rtsp_c;
3201
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3202
        break;
3203
    default:
3204
        goto fail;
3205
    }
3206

    
3207
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3208
             ipaddr, ntohs(dest_addr->sin_port),
3209
             c->stream->filename, stream_index, c->protocol);
3210

    
3211
    /* normally, no packets should be output here, but the packet size may be checked */
3212
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3213
        /* XXX: close stream */
3214
        goto fail;
3215
    }
3216
    av_set_parameters(ctx, NULL);
3217
    if (av_write_header(ctx) < 0) {
3218
    fail:
3219
        if (h)
3220
            url_close(h);
3221
        av_free(ctx);
3222
        return -1;
3223
    }
3224
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3225
    av_free(dummy_buf);
3226

    
3227
    c->rtp_ctx[stream_index] = ctx;
3228
    return 0;
3229
}
3230

    
3231
/********************************************************************/
3232
/* ffserver initialization */
3233

    
3234
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3235
{
3236
    AVStream *fst;
3237

    
3238
    fst = av_mallocz(sizeof(AVStream));
3239
    if (!fst)
3240
        return NULL;
3241
    fst->codec= avcodec_alloc_context();
3242
    fst->priv_data = av_mallocz(sizeof(FeedData));
3243
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3244
    fst->index = stream->nb_streams;
3245
    av_set_pts_info(fst, 33, 1, 90000);
3246
    stream->streams[stream->nb_streams++] = fst;
3247
    return fst;
3248
}
3249

    
3250
/* return the stream number in the feed */
3251
static int add_av_stream(FFStream *feed, AVStream *st)
3252
{
3253
    AVStream *fst;
3254
    AVCodecContext *av, *av1;
3255
    int i;
3256

    
3257
    av = st->codec;
3258
    for(i=0;i<feed->nb_streams;i++) {
3259
        st = feed->streams[i];
3260
        av1 = st->codec;
3261
        if (av1->codec_id == av->codec_id &&
3262
            av1->codec_type == av->codec_type &&
3263
            av1->bit_rate == av->bit_rate) {
3264

    
3265
            switch(av->codec_type) {
3266
            case CODEC_TYPE_AUDIO:
3267
                if (av1->channels == av->channels &&
3268
                    av1->sample_rate == av->sample_rate)
3269
                    goto found;
3270
                break;
3271
            case CODEC_TYPE_VIDEO:
3272
                if (av1->width == av->width &&
3273
                    av1->height == av->height &&
3274
                    av1->time_base.den == av->time_base.den &&
3275
                    av1->time_base.num == av->time_base.num &&
3276
                    av1->gop_size == av->gop_size)
3277
                    goto found;
3278
                break;
3279
            default:
3280
                abort();
3281
            }
3282
        }
3283
    }
3284

    
3285
    fst = add_av_stream1(feed, av);
3286
    if (!fst)
3287
        return -1;
3288
    return feed->nb_streams - 1;
3289
 found:
3290
    return i;
3291
}
3292

    
3293
static void remove_stream(FFStream *stream)
3294
{
3295
    FFStream **ps;
3296
    ps = &first_stream;
3297
    while (*ps != NULL) {
3298
        if (*ps == stream)
3299
            *ps = (*ps)->next;
3300
        else
3301
            ps = &(*ps)->next;
3302
    }
3303
}
3304

    
3305
/* specific mpeg4 handling : we extract the raw parameters */
3306
static void extract_mpeg4_header(AVFormatContext *infile)
3307
{
3308
    int mpeg4_count, i, size;
3309
    AVPacket pkt;
3310
    AVStream *st;
3311
    const uint8_t *p;
3312

    
3313
    mpeg4_count = 0;
3314
    for(i=0;i<infile->nb_streams;i++) {
3315
        st = infile->streams[i];
3316
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3317
            st->codec->extradata_size == 0) {
3318
            mpeg4_count++;
3319
        }
3320
    }
3321
    if (!mpeg4_count)
3322
        return;
3323

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

    
3354
/* compute the needed AVStream for each file */
3355
static void build_file_streams(void)
3356
{
3357
    FFStream *stream, *stream_next;
3358
    AVFormatContext *infile;
3359
    int i, ret;
3360

    
3361
    /* gather all streams */
3362
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3363
        stream_next = stream->next;
3364
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3365
            !stream->feed) {
3366
            /* the stream comes from a file */
3367
            /* try to open the file */
3368
            /* open stream */
3369
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3370
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3371
                /* specific case : if transport stream output to RTP,
3372
                   we use a raw transport stream reader */
3373
                stream->ap_in->mpeg2ts_raw = 1;
3374
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3375
            }
3376

    
3377
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3378
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3379
                http_log("could not open %s: %d\n", stream->feed_filename, ret);
3380
                /* remove stream (no need to spend more time on it) */
3381
            fail:
3382
                remove_stream(stream);
3383
            } else {
3384
                /* find all the AVStreams inside and reference them in
3385
                   'stream' */
3386
                if (av_find_stream_info(infile) < 0) {
3387
                    http_log("Could not find codec parameters from '%s'\n",
3388
                             stream->feed_filename);
3389
                    av_close_input_file(infile);
3390
                    goto fail;
3391
                }
3392
                extract_mpeg4_header(infile);
3393

    
3394
                for(i=0;i<infile->nb_streams;i++)
3395
                    add_av_stream1(stream, infile->streams[i]->codec);
3396

    
3397
                av_close_input_file(infile);
3398
            }
3399
        }
3400
    }
3401
}
3402

    
3403
/* compute the needed AVStream for each feed */
3404
static void build_feed_streams(void)
3405
{
3406
    FFStream *stream, *feed;
3407
    int i;
3408

    
3409
    /* gather all streams */
3410
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3411
        feed = stream->feed;
3412
        if (feed) {
3413
            if (!stream->is_feed) {
3414
                /* we handle a stream coming from a feed */
3415
                for(i=0;i<stream->nb_streams;i++)
3416
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3417
            }
3418
        }
3419
    }
3420

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

    
3432
    /* create feed files if needed */
3433
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3434
        int fd;
3435

    
3436
        if (url_exist(feed->feed_filename)) {
3437
            /* See if it matches */
3438
            AVFormatContext *s;
3439
            int matches = 0;
3440

    
3441
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3442
                /* Now see if it matches */
3443
                if (s->nb_streams == feed->nb_streams) {
3444
                    matches = 1;
3445
                    for(i=0;i<s->nb_streams;i++) {
3446
                        AVStream *sf, *ss;
3447
                        sf = feed->streams[i];
3448
                        ss = s->streams[i];
3449

    
3450
                        if (sf->index != ss->index ||
3451
                            sf->id != ss->id) {
3452
                            http_log("Index & Id do not match for stream %d (%s)\n",
3453
                                   i, feed->feed_filename);
3454
                            matches = 0;
3455
                        } else {
3456
                            AVCodecContext *ccf, *ccs;
3457

    
3458
                            ccf = sf->codec;
3459
                            ccs = ss->codec;
3460
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3461

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

    
3495
                av_close_input_file(s);
3496
            } else
3497
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3498
                        feed->feed_filename);
3499

    
3500
            if (!matches) {
3501
                if (feed->readonly) {
3502
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3503
                        feed->feed_filename);
3504
                    exit(1);
3505
                }
3506
                unlink(feed->feed_filename);
3507
            }
3508
        }
3509
        if (!url_exist(feed->feed_filename)) {
3510
            AVFormatContext s1, *s = &s1;
3511

    
3512
            if (feed->readonly) {
3513
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3514
                    feed->feed_filename);
3515
                exit(1);
3516
            }
3517

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

    
3548
        feed->feed_write_index = ffm_read_write_index(fd);
3549
        feed->feed_size = lseek(fd, 0, SEEK_END);
3550
        /* ensure that we do not wrap before the end of file */
3551
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3552
            feed->feed_max_size = feed->feed_size;
3553

    
3554
        close(fd);
3555
    }
3556
}
3557

    
3558
/* compute the bandwidth used by each stream */
3559
static void compute_bandwidth(void)
3560
{
3561
    unsigned bandwidth;
3562
    int i;
3563
    FFStream *stream;
3564

    
3565
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3566
        bandwidth = 0;
3567
        for(i=0;i<stream->nb_streams;i++) {
3568
            AVStream *st = stream->streams[i];
3569
            switch(st->codec->codec_type) {
3570
            case CODEC_TYPE_AUDIO:
3571
            case CODEC_TYPE_VIDEO:
3572
                bandwidth += st->codec->bit_rate;
3573
                break;
3574
            default:
3575
                break;
3576
            }
3577
        }
3578
        stream->bandwidth = (bandwidth + 999) / 1000;
3579
    }
3580
}
3581

    
3582
static void get_arg(char *buf, int buf_size, const char **pp)
3583
{
3584
    const char *p;
3585
    char *q;
3586
    int quote;
3587

    
3588
    p = *pp;
3589
    while (isspace(*p)) p++;
3590
    q = buf;
3591
    quote = 0;
3592
    if (*p == '\"' || *p == '\'')
3593
        quote = *p++;
3594
    for(;;) {
3595
        if (quote) {
3596
            if (*p == quote)
3597
                break;
3598
        } else {
3599
            if (isspace(*p))
3600
                break;
3601
        }
3602
        if (*p == '\0')
3603
            break;
3604
        if ((q - buf) < buf_size - 1)
3605
            *q++ = *p;
3606
        p++;
3607
    }
3608
    *q = '\0';
3609
    if (quote && *p == quote)
3610
        p++;
3611
    *pp = p;
3612
}
3613

    
3614
/* add a codec and set the default parameters */
3615
static void add_codec(FFStream *stream, AVCodecContext *av)
3616
{
3617
    AVStream *st;
3618

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

    
3653
        if (!av->nsse_weight)
3654
            av->nsse_weight = 8;
3655

    
3656
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3657
        av->me_method = ME_EPZS;
3658
        av->rc_buffer_aggressivity = 1.0;
3659

    
3660
        if (!av->rc_eq)
3661
            av->rc_eq = "tex^qComp";
3662
        if (!av->i_quant_factor)
3663
            av->i_quant_factor = -0.8;
3664
        if (!av->b_quant_factor)
3665
            av->b_quant_factor = 1.25;
3666
        if (!av->b_quant_offset)
3667
            av->b_quant_offset = 1.25;
3668
        if (!av->rc_max_rate)
3669
            av->rc_max_rate = av->bit_rate * 2;
3670

    
3671
        if (av->rc_max_rate && !av->rc_buffer_size) {
3672
            av->rc_buffer_size = av->rc_max_rate;
3673
        }
3674

    
3675

    
3676
        break;
3677
    default:
3678
        abort();
3679
    }
3680

    
3681
    st = av_mallocz(sizeof(AVStream));
3682
    if (!st)
3683
        return;
3684
    st->codec = avcodec_alloc_context();
3685
    stream->streams[stream->nb_streams++] = st;
3686
    memcpy(st->codec, av, sizeof(AVCodecContext));
3687
}
3688

    
3689
static int opt_audio_codec(const char *arg)
3690
{
3691
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3692

    
3693
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3694
        return CODEC_ID_NONE;
3695

    
3696
    return p->id;
3697
}
3698

    
3699
static int opt_video_codec(const char *arg)
3700
{
3701
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3702

    
3703
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3704
        return CODEC_ID_NONE;
3705

    
3706
    return p->id;
3707
}
3708

    
3709
/* simplistic plugin support */
3710

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

    
3723
    init_func = dlsym(dll, "ffserver_module_init");
3724
    if (!init_func) {
3725
        fprintf(stderr,
3726
                "%s: init function 'ffserver_module_init()' not found\n",
3727
                filename);
3728
        dlclose(dll);
3729
    }
3730

    
3731
    init_func();
3732
}
3733
#endif
3734

    
3735
static int ffserver_opt_default(const char *opt, const char *arg,
3736
                       AVCodecContext *avctx, int type)
3737
{
3738
    const AVOption *o  = NULL;
3739
    const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3740
    if(o2)
3741
        o = av_set_string2(avctx, opt, arg, 1);
3742
    if(!o)
3743
        return -1;
3744
    return 0;
3745
}
3746

    
3747
static int parse_ffconfig(const char *filename)
3748
{
3749
    FILE *f;
3750
    char line[1024];
3751
    char cmd[64];
3752
    char arg[1024];
3753
    const char *p;
3754
    int val, errors, line_num;
3755
    FFStream **last_stream, *stream, *redirect;
3756
    FFStream **last_feed, *feed;
3757
    AVCodecContext audio_enc, video_enc;
3758
    int audio_id, video_id;
3759

    
3760
    f = fopen(filename, "r");
3761
    if (!f) {
3762
        perror(filename);
3763
        return -1;
3764
    }
3765

    
3766
    errors = 0;
3767
    line_num = 0;
3768
    first_stream = NULL;
3769
    last_stream = &first_stream;
3770
    first_feed = NULL;
3771
    last_feed = &first_feed;
3772
    stream = NULL;
3773
    feed = NULL;
3774
    redirect = NULL;
3775
    audio_id = CODEC_ID_NONE;
3776
    video_id = CODEC_ID_NONE;
3777
    for(;;) {
3778
        if (fgets(line, sizeof(line), f) == NULL)
3779
            break;
3780
        line_num++;
3781
        p = line;
3782
        while (isspace(*p))
3783
            p++;
3784
        if (*p == '\0' || *p == '#')
3785
            continue;
3786

    
3787
        get_arg(cmd, sizeof(cmd), &p);
3788

    
3789
        if (!strcasecmp(cmd, "Port")) {
3790
            get_arg(arg, sizeof(arg), &p);
3791
            val = atoi(arg);
3792
            if (val < 1 || val > 65536) {
3793
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3794
                        filename, line_num, arg);
3795
                errors++;
3796
            }
3797
            my_http_addr.sin_port = htons(val);
3798
        } else if (!strcasecmp(cmd, "BindAddress")) {
3799
            get_arg(arg, sizeof(arg), &p);
3800
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3801
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3802
                        filename, line_num, arg);
3803
                errors++;
3804
            }
3805
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3806
            ffserver_daemon = 0;
3807
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3808
            get_arg(arg, sizeof(arg), &p);
3809
            val = atoi(arg);
3810
            if (val < 1 || val > 65536) {
3811
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3812
                        filename, line_num, arg);
3813
                errors++;
3814
            }
3815
            my_rtsp_addr.sin_port = htons(atoi(arg));
3816
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3817
            get_arg(arg, sizeof(arg), &p);
3818
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3819
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3820
                        filename, line_num, arg);
3821
                errors++;
3822
            }
3823
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3824
            get_arg(arg, sizeof(arg), &p);
3825
            val = atoi(arg);
3826
            if (val < 1 || val > 65536) {
3827
                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3828
                        filename, line_num, arg);
3829
                errors++;
3830
            }
3831
            nb_max_http_connections = val;
3832
        } else if (!strcasecmp(cmd, "MaxClients")) {
3833
            get_arg(arg, sizeof(arg), &p);
3834
            val = atoi(arg);
3835
            if (val < 1 || val > nb_max_http_connections) {
3836
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3837
                        filename, line_num, arg);
3838
                errors++;
3839
            } else {
3840
                nb_max_connections = val;
3841
            }
3842
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3843
            int64_t llval;
3844
            get_arg(arg, sizeof(arg), &p);
3845
            llval = atoll(arg);
3846
            if (llval < 10 || llval > 10000000) {
3847
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3848
                        filename, line_num, arg);
3849
                errors++;
3850
            } else
3851
                max_bandwidth = llval;
3852
        } else if (!strcasecmp(cmd, "CustomLog")) {
3853
            if (!ffserver_debug)
3854
                get_arg(logfilename, sizeof(logfilename), &p);
3855
        } else if (!strcasecmp(cmd, "<Feed")) {
3856
            /*********************************************/
3857
            /* Feed related options */
3858
            char *q;
3859
            if (stream || feed) {
3860
                fprintf(stderr, "%s:%d: Already in a tag\n",
3861
                        filename, line_num);
3862
            } else {
3863
                feed = av_mallocz(sizeof(FFStream));
3864
                /* add in stream list */
3865
                *last_stream = feed;
3866
                last_stream = &feed->next;
3867
                /* add in feed list */
3868
                *last_feed = feed;
3869
                last_feed = &feed->next_feed;
3870

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

    
3887
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3888

    
3889
                for (i = 0; i < 62; i++) {
3890
                    get_arg(arg, sizeof(arg), &p);
3891
                    if (!arg[0])
3892
                        break;
3893

    
3894
                    feed->child_argv[i] = av_strdup(arg);
3895
                }
3896

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

    
3899
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3900
                    "http://%s:%d/%s",
3901
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3902
                    inet_ntoa(my_http_addr.sin_addr),
3903
                    ntohs(my_http_addr.sin_port), feed->filename);
3904
            }
3905
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3906
            if (feed) {
3907
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3908
                feed->readonly = 1;
3909
            } else if (stream) {
3910
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3911
            }
3912
        } else if (!strcasecmp(cmd, "File")) {
3913
            if (feed) {
3914
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3915
            } else if (stream)
3916
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3917
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3918
            if (feed) {
3919
                char *p1;
3920
                double fsize;
3921

    
3922
                get_arg(arg, sizeof(arg), &p);
3923
                p1 = arg;
3924
                fsize = strtod(p1, &p1);
3925
                switch(toupper(*p1)) {
3926
                case 'K':
3927
                    fsize *= 1024;
3928
                    break;
3929
                case 'M':
3930
                    fsize *= 1024 * 1024;
3931
                    break;
3932
                case 'G':
3933
                    fsize *= 1024 * 1024 * 1024;
3934
                    break;
3935
                }
3936
                feed->feed_max_size = (int64_t)fsize;
3937
            }
3938
        } else if (!strcasecmp(cmd, "</Feed>")) {
3939
            if (!feed) {
3940
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3941
                        filename, line_num);
3942
                errors++;
3943
            }
3944
            feed = NULL;
3945
        } else if (!strcasecmp(cmd, "<Stream")) {
3946
            /*********************************************/
3947
            /* Stream related options */
3948
            char *q;
3949
            if (stream || feed) {
3950
                fprintf(stderr, "%s:%d: Already in a tag\n",
3951
                        filename, line_num);
3952
            } else {
3953
                const AVClass *class;
3954
                stream = av_mallocz(sizeof(FFStream));
3955
                *last_stream = stream;
3956
                last_stream = &stream->next;
3957

    
3958
                get_arg(stream->filename, sizeof(stream->filename), &p);
3959
                q = strrchr(stream->filename, '>');
3960
                if (*q)
3961
                    *q = '\0';
3962
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3963
                /* fetch avclass so AVOption works
3964
                 * FIXME try to use avcodec_get_context_defaults2
3965
                 * without changing defaults too much */
3966
                avcodec_get_context_defaults(&video_enc);
3967
                class = video_enc.av_class;
3968
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3969
                memset(&video_enc, 0, sizeof(AVCodecContext));
3970
                audio_enc.av_class = class;
3971
                video_enc.av_class = class;
3972
                audio_id = CODEC_ID_NONE;
3973
                video_id = CODEC_ID_NONE;
3974
                if (stream->fmt) {
3975
                    audio_id = stream->fmt->audio_codec;
3976
                    video_id = stream->fmt->video_codec;
3977
                }
3978
            }
3979
        } else if (!strcasecmp(cmd, "Feed")) {
3980
            get_arg(arg, sizeof(arg), &p);
3981
            if (stream) {
3982
                FFStream *sfeed;
3983

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

    
4094
                get_arg(arg, sizeof(arg), &p);
4095

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

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

    
4269
            get_arg(arg, sizeof(arg), &p);
4270

    
4271
            if (resolve_host(&acl.first, arg) != 0) {
4272
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4273
                        filename, line_num, arg);
4274
                errors++;
4275
            } else
4276
                acl.last = acl.first;
4277

    
4278
            get_arg(arg, sizeof(arg), &p);
4279

    
4280
            if (arg[0]) {
4281
                if (resolve_host(&acl.last, arg) != 0) {
4282
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4283
                            filename, line_num, arg);
4284
                    errors++;
4285
                }
4286
            }
4287

    
4288
            if (!errors) {
4289
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4290
                IPAddressACL **naclp = 0;
4291

    
4292
                acl.next = 0;
4293
                *nacl = acl;
4294

    
4295
                if (stream)
4296
                    naclp = &stream->acl;
4297
                else if (feed)
4298
                    naclp = &feed->acl;
4299
                else {
4300
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4301
                            filename, line_num);
4302
                    errors++;
4303
                }
4304

    
4305
                if (naclp) {
4306
                    while (*naclp)
4307
                        naclp = &(*naclp)->next;
4308

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

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

    
4410
    fclose(f);
4411
    if (errors)
4412
        return -1;
4413
    else
4414
        return 0;
4415
}
4416

    
4417
static void handle_child_exit(int sig)
4418
{
4419
    pid_t pid;
4420
    int status;
4421

    
4422
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4423
        FFStream *feed;
4424

    
4425
        for (feed = first_feed; feed; feed = feed->next) {
4426
            if (feed->pid == pid) {
4427
                int uptime = time(0) - feed->pid_start;
4428

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

    
4432
                if (uptime < 30)
4433
                    /* Turn off any more restarts */
4434
                    feed->child_argv = 0;
4435
            }
4436
        }
4437
    }
4438

    
4439
    need_to_start_children = 1;
4440
}
4441

    
4442
static void opt_debug()
4443
{
4444
    ffserver_debug = 1;
4445
    ffserver_daemon = 0;
4446
    logfilename[0] = '-';
4447
}
4448

    
4449
static void opt_show_help(void)
4450
{
4451
    printf("usage: ffserver [options]\n"
4452
           "Hyper fast multi format Audio/Video streaming server\n");
4453
    printf("\n");
4454
    show_help_options(options, "Main options:\n", 0, 0);
4455
}
4456

    
4457
static const OptionDef options[] = {
4458
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4459
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4460
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4461
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4462
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4463
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4464
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4465
    { NULL },
4466
};
4467

    
4468
int main(int argc, char **argv)
4469
{
4470
    struct sigaction sigact;
4471

    
4472
    av_register_all();
4473

    
4474
    show_banner();
4475

    
4476
    config_filename = "/etc/ffserver.conf";
4477

    
4478
    my_program_name = argv[0];
4479
    my_program_dir = getcwd(0, 0);
4480
    ffserver_daemon = 1;
4481

    
4482
    parse_options(argc, argv, options, NULL);
4483

    
4484
    unsetenv("http_proxy");             /* Kill the http_proxy */
4485

    
4486
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4487

    
4488
    memset(&sigact, 0, sizeof(sigact));
4489
    sigact.sa_handler = handle_child_exit;
4490
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4491
    sigaction(SIGCHLD, &sigact, 0);
4492

    
4493
    if (parse_ffconfig(config_filename) < 0) {
4494
        fprintf(stderr, "Incorrect config file - exiting.\n");
4495
        exit(1);
4496
    }
4497

    
4498
    /* open log file if needed */
4499
    if (logfilename[0] != '\0') {
4500
        if (!strcmp(logfilename, "-"))
4501
            logfile = stdout;
4502
        else
4503
            logfile = fopen(logfilename, "a");
4504
        av_log_set_callback(http_av_log);
4505
    }
4506

    
4507
    build_file_streams();
4508

    
4509
    build_feed_streams();
4510

    
4511
    compute_bandwidth();
4512

    
4513
    /* put the process in background and detach it from its TTY */
4514
    if (ffserver_daemon) {
4515
        int pid;
4516

    
4517
        pid = fork();
4518
        if (pid < 0) {
4519
            perror("fork");
4520
            exit(1);
4521
        } else if (pid > 0) {
4522
            /* parent : exit */
4523
            exit(0);
4524
        } else {
4525
            /* child */
4526
            setsid();
4527
            close(0);
4528
            open("/dev/null", O_RDWR);
4529
            if (strcmp(logfilename, "-") != 0) {
4530
                close(1);
4531
                dup(0);
4532
            }
4533
            close(2);
4534
            dup(0);
4535
        }
4536
    }
4537

    
4538
    /* signal init */
4539
    signal(SIGPIPE, SIG_IGN);
4540

    
4541
    if (ffserver_daemon)
4542
        chdir("/");
4543

    
4544
    if (http_server() < 0) {
4545
        http_log("Could not start server\n");
4546
        exit(1);
4547
    }
4548

    
4549
    return 0;
4550
}