Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 959da985

History | View | Annotate | Download (150 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
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35
#include "libavformat/rtp.h"
36
#include "libavformat/rtsp.h"
37
#include "libavutil/avstring.h"
38
#include "libavutil/random.h"
39
#include "libavcodec/opt.h"
40
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
44
#ifdef HAVE_POLL_H
45
#include <poll.h>
46
#endif
47
#include <errno.h>
48
#include <sys/time.h>
49
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
50
#include <time.h>
51
#include <sys/wait.h>
52
#include <signal.h>
53
#ifdef HAVE_DLFCN_H
54
#include <dlfcn.h>
55
#endif
56

    
57
#include "cmdutils.h"
58

    
59
#undef exit
60

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

    
64
static const OptionDef options[];
65

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

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

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

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

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

    
97
#define IOBUFFER_INIT_SIZE 8192
98

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

    
103
#define SYNC_TIMEOUT (10 * 1000)
104

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
306
static AVRandomState random_state;
307

    
308
static FILE *logfile = NULL;
309

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

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

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

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

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

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

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

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

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

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

    
391

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

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

    
401
            feed->pid = fork();
402

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

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

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

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

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

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

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

    
444
                signal(SIGPIPE, SIG_DFL);
445

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

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

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

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

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

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

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

    
483
    return server_fd;
484
}
485

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

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

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

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

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

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

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

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

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

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

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

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

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

    
571
    http_log("FFserver started.\n");
572

    
573
    start_children(first_feed);
574

    
575
    start_multicast();
576

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

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

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

    
649
        cur_time = av_gettime() / 1000;
650

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

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

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

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

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

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

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

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

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

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

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

    
733
    start_wait_request(c, is_rtsp);
734

    
735
    return;
736

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

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

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

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

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

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

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

    
798
    ctx = &c->fmt_ctx;
799

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1022
                q += 20;
1023

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

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

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

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

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

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

    
1048
        p++;
1049
    }
1050

    
1051
    return 0;
1052
}
1053

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

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

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

    
1069
        /* Potential stream */
1070

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

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

    
1088
    return best;
1089
}
1090

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

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

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

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

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

    
1126
    return action_required;
1127
}
1128

    
1129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1283
        p++;
1284
    }
1285

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

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

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

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

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

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

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

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

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

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

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

    
1393
            p++;
1394
        }
1395

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

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

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

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

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

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

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

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

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

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

    
1501
    stream->conns_served++;
1502

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

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

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

    
1524
                p++;
1525
            }
1526

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

    
1530
                logline += 17;
1531

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1804
                parameters[0] = 0;
1805

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2030

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

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

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

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

    
2070
        c->got_key_frame = 0;
2071

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2543
/********************************************************************/
2544
/* RTSP handling */
2545

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2732
    return strlen(*pbuffer);
2733
}
2734

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

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

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

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

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

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

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

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

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

    
2802
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPLowerTransport lower_transport)
2803
{
2804
    RTSPTransportField *th;
2805
    int i;
2806

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2950

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

    
2954

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

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

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

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

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

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

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

    
3012
    rtp_c->state = HTTPSTATE_SEND_DATA;
3013

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

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

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

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

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

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

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

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

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

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

    
3069

    
3070
/********************************************************************/
3071
/* RTP handling */
3072

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

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

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

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

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

    
3122
    current_bandwidth += stream->bandwidth;
3123

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

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

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

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

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

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

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

    
3175
    switch(c->rtp_protocol) {
3176
    case RTSP_LOWER_TRANSPORT_UDP:
3177
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3178
        /* RTP/UDP case */
3179

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

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

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

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

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

    
3232
/********************************************************************/
3233
/* ffserver initialization */
3234

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3555
        close(fd);
3556
    }
3557
}
3558

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

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

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

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

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

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

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

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

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

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

    
3676

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

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

    
3690
static enum CodecID opt_audio_codec(const char *arg)
3691
{
3692
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3693

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

    
3697
    return p->id;
3698
}
3699

    
3700
static enum CodecID opt_video_codec(const char *arg)
3701
{
3702
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3703

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

    
3707
    return p->id;
3708
}
3709

    
3710
/* simplistic plugin support */
3711

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

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

    
3732
    init_func();
3733
}
3734
#endif
3735

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4440
    need_to_start_children = 1;
4441
}
4442

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

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

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

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

    
4473
    av_register_all();
4474

    
4475
    show_banner();
4476

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

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

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

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

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

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

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

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

    
4508
    build_file_streams();
4509

    
4510
    build_feed_streams();
4511

    
4512
    compute_bandwidth();
4513

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

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

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

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

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

    
4550
    return 0;
4551
}