Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ f10d55ed

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

    
53
#include "cmdutils.h"
54

    
55
#undef exit
56

    
57
const char program_name[] = "FFserver";
58
const int program_birth_year = 2000;
59

    
60
static const OptionDef options[];
61

    
62
/* maximum number of simultaneous HTTP connections */
63
#define HTTP_MAX_CONNECTIONS 2000
64

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

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

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

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

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

    
96
#define IOBUFFER_INIT_SIZE 8192
97

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

    
102
#define SYNC_TIMEOUT (10 * 1000)
103

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
295
static int nb_max_connections = 5;
296
static int nb_connections;
297

    
298
static uint64_t max_bandwidth = 1000;
299
static uint64_t current_bandwidth;
300

    
301
static int64_t cur_time;           // Making this global saves on passing it around everywhere
302

    
303
static AVRandomState random_state;
304

    
305
static FILE *logfile = NULL;
306

    
307
static char *ctime1(char *buf2)
308
{
309
    time_t ti;
310
    char *p;
311

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

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

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

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

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

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

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

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

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

    
388

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

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

    
398
            feed->pid = fork();
399

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

    
410
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
411

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

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

    
425
                for (i = 3; i < 256; i++)
426
                    close(i);
427

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

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

    
441
                signal(SIGPIPE, SIG_DFL);
442

    
443
                execvp(pathname, feed->child_argv);
444

    
445
                _exit(1);
446
            }
447
        }
448
    }
449
}
450

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

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

    
462
    tmp = 1;
463
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
464

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

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

    
480
    return server_fd;
481
}
482

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

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

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

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

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

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

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

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

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

    
546
    if (my_http_addr.sin_port) {
547
        server_fd = socket_open_listen(&my_http_addr);
548
        if (server_fd < 0)
549
            return -1;
550
    }
551

    
552
    if (my_rtsp_addr.sin_port) {
553
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
554
        if (rtsp_server_fd < 0)
555
            return -1;
556
    }
557

    
558
    if (!rtsp_server_fd && !server_fd) {
559
        http_log("HTTP and RTSP disabled.\n");
560
        return -1;
561
    }
562

    
563
    http_log("ffserver started.\n");
564

    
565
    start_children(first_feed);
566

    
567
    start_multicast();
568

    
569
    for(;;) {
570
        poll_entry = poll_table;
571
        if (server_fd) {
572
            poll_entry->fd = server_fd;
573
            poll_entry->events = POLLIN;
574
            poll_entry++;
575
        }
576
        if (rtsp_server_fd) {
577
            poll_entry->fd = rtsp_server_fd;
578
            poll_entry->events = POLLIN;
579
            poll_entry++;
580
        }
581

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

    
632
        /* wait for an event on one connection. We poll at least every
633
           second to handle timeouts */
634
        do {
635
            ret = poll(poll_table, poll_entry - poll_table, delay);
636
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
637
                ff_neterrno() != FF_NETERROR(EINTR))
638
                return -1;
639
        } while (ret < 0);
640

    
641
        cur_time = av_gettime() / 1000;
642

    
643
        if (need_to_start_children) {
644
            need_to_start_children = 0;
645
            start_children(first_feed);
646
        }
647

    
648
        /* now handle the events */
649
        for(c = first_http_ctx; c != NULL; c = c_next) {
650
            c_next = c->next;
651
            if (handle_connection(c) < 0) {
652
                /* close and free the connection */
653
                log_connection(c);
654
                close_connection(c);
655
            }
656
        }
657

    
658
        poll_entry = poll_table;
659
        if (server_fd) {
660
            /* new HTTP connection request ? */
661
            if (poll_entry->revents & POLLIN)
662
                new_connection(server_fd, 0);
663
            poll_entry++;
664
        }
665
        if (rtsp_server_fd) {
666
            /* new RTSP connection request ? */
667
            if (poll_entry->revents & POLLIN)
668
                new_connection(rtsp_server_fd, 1);
669
        }
670
    }
671
}
672

    
673
/* start waiting for a new HTTP/RTSP request */
674
static void start_wait_request(HTTPContext *c, int is_rtsp)
675
{
676
    c->buffer_ptr = c->buffer;
677
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
678

    
679
    if (is_rtsp) {
680
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
681
        c->state = RTSPSTATE_WAIT_REQUEST;
682
    } else {
683
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
684
        c->state = HTTPSTATE_WAIT_REQUEST;
685
    }
686
}
687

    
688
static void new_connection(int server_fd, int is_rtsp)
689
{
690
    struct sockaddr_in from_addr;
691
    int fd, len;
692
    HTTPContext *c = NULL;
693

    
694
    len = sizeof(from_addr);
695
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
696
                &len);
697
    if (fd < 0) {
698
        http_log("error during accept %s\n", strerror(errno));
699
        return;
700
    }
701
    ff_socket_nonblock(fd, 1);
702

    
703
    /* XXX: should output a warning page when coming
704
       close to the connection limit */
705
    if (nb_connections >= nb_max_connections)
706
        goto fail;
707

    
708
    /* add a new connection */
709
    c = av_mallocz(sizeof(HTTPContext));
710
    if (!c)
711
        goto fail;
712

    
713
    c->fd = fd;
714
    c->poll_entry = NULL;
715
    c->from_addr = from_addr;
716
    c->buffer_size = IOBUFFER_INIT_SIZE;
717
    c->buffer = av_malloc(c->buffer_size);
718
    if (!c->buffer)
719
        goto fail;
720

    
721
    c->next = first_http_ctx;
722
    first_http_ctx = c;
723
    nb_connections++;
724

    
725
    start_wait_request(c, is_rtsp);
726

    
727
    return;
728

    
729
 fail:
730
    if (c) {
731
        av_free(c->buffer);
732
        av_free(c);
733
    }
734
    closesocket(fd);
735
}
736

    
737
static void close_connection(HTTPContext *c)
738
{
739
    HTTPContext **cp, *c1;
740
    int i, nb_streams;
741
    AVFormatContext *ctx;
742
    URLContext *h;
743
    AVStream *st;
744

    
745
    /* remove connection from list */
746
    cp = &first_http_ctx;
747
    while ((*cp) != NULL) {
748
        c1 = *cp;
749
        if (c1 == c)
750
            *cp = c->next;
751
        else
752
            cp = &c1->next;
753
    }
754

    
755
    /* remove references, if any (XXX: do it faster) */
756
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
757
        if (c1->rtsp_c == c)
758
            c1->rtsp_c = NULL;
759
    }
760

    
761
    /* remove connection associated resources */
762
    if (c->fd >= 0)
763
        closesocket(c->fd);
764
    if (c->fmt_in) {
765
        /* close each frame parser */
766
        for(i=0;i<c->fmt_in->nb_streams;i++) {
767
            st = c->fmt_in->streams[i];
768
            if (st->codec->codec)
769
                avcodec_close(st->codec);
770
        }
771
        av_close_input_file(c->fmt_in);
772
    }
773

    
774
    /* free RTP output streams if any */
775
    nb_streams = 0;
776
    if (c->stream)
777
        nb_streams = c->stream->nb_streams;
778

    
779
    for(i=0;i<nb_streams;i++) {
780
        ctx = c->rtp_ctx[i];
781
        if (ctx) {
782
            av_write_trailer(ctx);
783
            av_free(ctx);
784
        }
785
        h = c->rtp_handles[i];
786
        if (h)
787
            url_close(h);
788
    }
789

    
790
    ctx = &c->fmt_ctx;
791

    
792
    if (!c->last_packet_sent) {
793
        if (ctx->oformat) {
794
            /* prepare header */
795
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
796
                av_write_trailer(ctx);
797
                av_freep(&c->pb_buffer);
798
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
799
            }
800
        }
801
    }
802

    
803
    for(i=0; i<ctx->nb_streams; i++)
804
        av_free(ctx->streams[i]);
805

    
806
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
807
        current_bandwidth -= c->stream->bandwidth;
808

    
809
    /* signal that there is no feed if we are the feeder socket */
810
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
811
        c->stream->feed_opened = 0;
812
        close(c->feed_fd);
813
    }
814

    
815
    av_freep(&c->pb_buffer);
816
    av_freep(&c->packet_buffer);
817
    av_free(c->buffer);
818
    av_free(c);
819
    nb_connections--;
820
}
821

    
822
static int handle_connection(HTTPContext *c)
823
{
824
    int len, ret;
825

    
826
    switch(c->state) {
827
    case HTTPSTATE_WAIT_REQUEST:
828
    case RTSPSTATE_WAIT_REQUEST:
829
        /* timeout ? */
830
        if ((c->timeout - cur_time) < 0)
831
            return -1;
832
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
833
            return -1;
834

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

    
869
    case HTTPSTATE_SEND_HEADER:
870
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
871
            return -1;
872

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

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

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

    
935
        /* nothing to do, we'll be waken up by incoming feed packets */
936
        break;
937

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

    
999
static int extract_rates(char *rates, int ratelen, const char *request)
1000
{
1001
    const char *p;
1002

    
1003
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1004
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1005
            const char *q = p + 7;
1006

    
1007
            while (*q && *q != '\n' && isspace(*q))
1008
                q++;
1009

    
1010
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1011
                int stream_no;
1012
                int rate_no;
1013

    
1014
                q += 20;
1015

    
1016
                memset(rates, 0xff, ratelen);
1017

    
1018
                while (1) {
1019
                    while (*q && *q != '\n' && *q != ':')
1020
                        q++;
1021

    
1022
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1023
                        break;
1024

    
1025
                    stream_no--;
1026
                    if (stream_no < ratelen && stream_no >= 0)
1027
                        rates[stream_no] = rate_no;
1028

    
1029
                    while (*q && *q != '\n' && !isspace(*q))
1030
                        q++;
1031
                }
1032

    
1033
                return 1;
1034
            }
1035
        }
1036
        p = strchr(p, '\n');
1037
        if (!p)
1038
            break;
1039

    
1040
        p++;
1041
    }
1042

    
1043
    return 0;
1044
}
1045

    
1046
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1047
{
1048
    int i;
1049
    int best_bitrate = 100000000;
1050
    int best = -1;
1051

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

    
1055
        if (feed_codec->codec_id != codec->codec_id ||
1056
            feed_codec->sample_rate != codec->sample_rate ||
1057
            feed_codec->width != codec->width ||
1058
            feed_codec->height != codec->height)
1059
            continue;
1060

    
1061
        /* Potential stream */
1062

    
1063
        /* We want the fastest stream less than bit_rate, or the slowest
1064
         * faster than bit_rate
1065
         */
1066

    
1067
        if (feed_codec->bit_rate <= bit_rate) {
1068
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1069
                best_bitrate = feed_codec->bit_rate;
1070
                best = i;
1071
            }
1072
        } else {
1073
            if (feed_codec->bit_rate < best_bitrate) {
1074
                best_bitrate = feed_codec->bit_rate;
1075
                best = i;
1076
            }
1077
        }
1078
    }
1079

    
1080
    return best;
1081
}
1082

    
1083
static int modify_current_stream(HTTPContext *c, char *rates)
1084
{
1085
    int i;
1086
    FFStream *req = c->stream;
1087
    int action_required = 0;
1088

    
1089
    /* Not much we can do for a feed */
1090
    if (!req->feed)
1091
        return 0;
1092

    
1093
    for (i = 0; i < req->nb_streams; i++) {
1094
        AVCodecContext *codec = req->streams[i]->codec;
1095

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

    
1114
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1115
            action_required = 1;
1116
    }
1117

    
1118
    return action_required;
1119
}
1120

    
1121

    
1122
static void do_switch_stream(HTTPContext *c, int i)
1123
{
1124
    if (c->switch_feed_streams[i] >= 0) {
1125
#ifdef PHILIP
1126
        c->feed_streams[i] = c->switch_feed_streams[i];
1127
#endif
1128

    
1129
        /* Now update the stream */
1130
    }
1131
    c->switch_feed_streams[i] = -1;
1132
}
1133

    
1134
/* XXX: factorize in utils.c ? */
1135
/* XXX: take care with different space meaning */
1136
static void skip_spaces(const char **pp)
1137
{
1138
    const char *p;
1139
    p = *pp;
1140
    while (*p == ' ' || *p == '\t')
1141
        p++;
1142
    *pp = p;
1143
}
1144

    
1145
static void get_word(char *buf, int buf_size, const char **pp)
1146
{
1147
    const char *p;
1148
    char *q;
1149

    
1150
    p = *pp;
1151
    skip_spaces(&p);
1152
    q = buf;
1153
    while (!isspace(*p) && *p != '\0') {
1154
        if ((q - buf) < buf_size - 1)
1155
            *q++ = *p;
1156
        p++;
1157
    }
1158
    if (buf_size > 0)
1159
        *q = '\0';
1160
    *pp = p;
1161
}
1162

    
1163
static int validate_acl(FFStream *stream, HTTPContext *c)
1164
{
1165
    enum IPAddressAction last_action = IP_DENY;
1166
    IPAddressACL *acl;
1167
    struct in_addr *src = &c->from_addr.sin_addr;
1168
    unsigned long src_addr = src->s_addr;
1169

    
1170
    for (acl = stream->acl; acl; acl = acl->next) {
1171
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1172
            return (acl->action == IP_ALLOW) ? 1 : 0;
1173
        last_action = acl->action;
1174
    }
1175

    
1176
    /* Nothing matched, so return not the last action */
1177
    return (last_action == IP_DENY) ? 1 : 0;
1178
}
1179

    
1180
/* compute the real filename of a file by matching it without its
1181
   extensions to all the stream filenames */
1182
static void compute_real_filename(char *filename, int max_size)
1183
{
1184
    char file1[1024];
1185
    char file2[1024];
1186
    char *p;
1187
    FFStream *stream;
1188

    
1189
    /* compute filename by matching without the file extensions */
1190
    av_strlcpy(file1, filename, sizeof(file1));
1191
    p = strrchr(file1, '.');
1192
    if (p)
1193
        *p = '\0';
1194
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1195
        av_strlcpy(file2, stream->filename, sizeof(file2));
1196
        p = strrchr(file2, '.');
1197
        if (p)
1198
            *p = '\0';
1199
        if (!strcmp(file1, file2)) {
1200
            av_strlcpy(filename, stream->filename, max_size);
1201
            break;
1202
        }
1203
    }
1204
}
1205

    
1206
enum RedirType {
1207
    REDIR_NONE,
1208
    REDIR_ASX,
1209
    REDIR_RAM,
1210
    REDIR_ASF,
1211
    REDIR_RTSP,
1212
    REDIR_SDP,
1213
};
1214

    
1215
/* parse http request and prepare header */
1216
static int http_parse_request(HTTPContext *c)
1217
{
1218
    char *p;
1219
    enum RedirType redir_type;
1220
    char cmd[32];
1221
    char info[1024], filename[1024];
1222
    char url[1024], *q;
1223
    char protocol[32];
1224
    char msg[1024];
1225
    const char *mime_type;
1226
    FFStream *stream;
1227
    int i;
1228
    char ratebuf[32];
1229
    char *useragent = 0;
1230

    
1231
    p = c->buffer;
1232
    get_word(cmd, sizeof(cmd), (const char **)&p);
1233
    av_strlcpy(c->method, cmd, sizeof(c->method));
1234

    
1235
    if (!strcmp(cmd, "GET"))
1236
        c->post = 0;
1237
    else if (!strcmp(cmd, "POST"))
1238
        c->post = 1;
1239
    else
1240
        return -1;
1241

    
1242
    get_word(url, sizeof(url), (const char **)&p);
1243
    av_strlcpy(c->url, url, sizeof(c->url));
1244

    
1245
    get_word(protocol, sizeof(protocol), (const char **)&p);
1246
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1247
        return -1;
1248

    
1249
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1250

    
1251
    if (ffserver_debug)
1252
        http_log("New connection: %s %s\n", cmd, url);
1253

    
1254
    /* find the filename and the optional info string in the request */
1255
    p = strchr(url, '?');
1256
    if (p) {
1257
        av_strlcpy(info, p, sizeof(info));
1258
        *p = '\0';
1259
    } else
1260
        info[0] = '\0';
1261

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

    
1264
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1265
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1266
            useragent = p + 11;
1267
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1268
                useragent++;
1269
            break;
1270
        }
1271
        p = strchr(p, '\n');
1272
        if (!p)
1273
            break;
1274

    
1275
        p++;
1276
    }
1277

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

    
1297
    // "redirect" / request to index.html
1298
    if (!strlen(filename))
1299
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1300

    
1301
    stream = first_stream;
1302
    while (stream != NULL) {
1303
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1304
            break;
1305
        stream = stream->next;
1306
    }
1307
    if (stream == NULL) {
1308
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1309
        goto send_error;
1310
    }
1311

    
1312
    c->stream = stream;
1313
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1314
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1315

    
1316
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1317
        c->http_error = 301;
1318
        q = c->buffer;
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1320
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1322
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1323
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1324
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1325
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1326

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

    
1334
    /* If this is WMP, get the rate information */
1335
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1336
        if (modify_current_stream(c, ratebuf)) {
1337
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1338
                if (c->switch_feed_streams[i] >= 0)
1339
                    do_switch_stream(c, i);
1340
            }
1341
        }
1342
    }
1343

    
1344
    /* If already streaming this feed, do not let start another feeder. */
1345
    if (stream->feed_opened) {
1346
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1347
        http_log("feed %s already being received\n", stream->feed_filename);
1348
        goto send_error;
1349
    }
1350

    
1351
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1352
        current_bandwidth += stream->bandwidth;
1353

    
1354
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1355
        c->http_error = 200;
1356
        q = c->buffer;
1357
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1358
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1359
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1360
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1361
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1362
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
1363
            current_bandwidth, max_bandwidth);
1364
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1365

    
1366
        /* prepare output buffer */
1367
        c->buffer_ptr = c->buffer;
1368
        c->buffer_end = q;
1369
        c->state = HTTPSTATE_SEND_HEADER;
1370
        return 0;
1371
    }
1372

    
1373
    if (redir_type != REDIR_NONE) {
1374
        char *hostinfo = 0;
1375

    
1376
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1377
            if (strncasecmp(p, "Host:", 5) == 0) {
1378
                hostinfo = p + 5;
1379
                break;
1380
            }
1381
            p = strchr(p, '\n');
1382
            if (!p)
1383
                break;
1384

    
1385
            p++;
1386
        }
1387

    
1388
        if (hostinfo) {
1389
            char *eoh;
1390
            char hostbuf[260];
1391

    
1392
            while (isspace(*hostinfo))
1393
                hostinfo++;
1394

    
1395
            eoh = strchr(hostinfo, '\n');
1396
            if (eoh) {
1397
                if (eoh[-1] == '\r')
1398
                    eoh--;
1399

    
1400
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1401
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1402
                    hostbuf[eoh - hostinfo] = 0;
1403

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

    
1456
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1457
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1458
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1459

    
1460
                            len = sizeof(my_addr);
1461
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1462

    
1463
                            /* XXX: should use a dynamic buffer */
1464
                            sdp_data_size = prepare_sdp_description(stream,
1465
                                                                    &sdp_data,
1466
                                                                    my_addr.sin_addr);
1467
                            if (sdp_data_size > 0) {
1468
                                memcpy(q, sdp_data, sdp_data_size);
1469
                                q += sdp_data_size;
1470
                                *q = '\0';
1471
                                av_free(sdp_data);
1472
                            }
1473
                        }
1474
                        break;
1475
                    default:
1476
                        abort();
1477
                        break;
1478
                    }
1479

    
1480
                    /* prepare output buffer */
1481
                    c->buffer_ptr = c->buffer;
1482
                    c->buffer_end = q;
1483
                    c->state = HTTPSTATE_SEND_HEADER;
1484
                    return 0;
1485
                }
1486
            }
1487
        }
1488

    
1489
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1490
        goto send_error;
1491
    }
1492

    
1493
    stream->conns_served++;
1494

    
1495
    /* XXX: add there authenticate and IP match */
1496

    
1497
    if (c->post) {
1498
        /* if post, it means a feed is being sent */
1499
        if (!stream->is_feed) {
1500
            /* However it might be a status report from WMP! Lets log the data
1501
             * as it might come in handy one day
1502
             */
1503
            char *logline = 0;
1504
            int client_id = 0;
1505

    
1506
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1507
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1508
                    logline = p;
1509
                    break;
1510
                }
1511
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1512
                    client_id = strtol(p + 18, 0, 10);
1513
                p = strchr(p, '\n');
1514
                if (!p)
1515
                    break;
1516

    
1517
                p++;
1518
            }
1519

    
1520
            if (logline) {
1521
                char *eol = strchr(logline, '\n');
1522

    
1523
                logline += 17;
1524

    
1525
                if (eol) {
1526
                    if (eol[-1] == '\r')
1527
                        eol--;
1528
                    http_log("%.*s\n", (int) (eol - logline), logline);
1529
                    c->suppress_log = 1;
1530
                }
1531
            }
1532

    
1533
#ifdef DEBUG_WMP
1534
            http_log("\nGot request:\n%s\n", c->buffer);
1535
#endif
1536

    
1537
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1538
                HTTPContext *wmpc;
1539

    
1540
                /* Now we have to find the client_id */
1541
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1542
                    if (wmpc->wmp_client_id == client_id)
1543
                        break;
1544
                }
1545

    
1546
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1547
                    wmpc->switch_pending = 1;
1548
            }
1549

    
1550
            snprintf(msg, sizeof(msg), "POST command not handled");
1551
            c->stream = 0;
1552
            goto send_error;
1553
        }
1554
        if (http_start_receive_data(c) < 0) {
1555
            snprintf(msg, sizeof(msg), "could not open feed");
1556
            goto send_error;
1557
        }
1558
        c->http_error = 0;
1559
        c->state = HTTPSTATE_RECEIVE_DATA;
1560
        return 0;
1561
    }
1562

    
1563
#ifdef DEBUG_WMP
1564
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1565
        http_log("\nGot request:\n%s\n", c->buffer);
1566
#endif
1567

    
1568
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1569
        goto send_status;
1570

    
1571
    /* open input stream */
1572
    if (open_input_stream(c, info) < 0) {
1573
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1574
        goto send_error;
1575
    }
1576

    
1577
    /* prepare http header */
1578
    q = c->buffer;
1579
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1580
    mime_type = c->stream->fmt->mime_type;
1581
    if (!mime_type)
1582
        mime_type = "application/x-octet-stream";
1583
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1584

    
1585
    /* for asf, we need extra headers */
1586
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1587
        /* Need to allocate a client id */
1588

    
1589
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1590

    
1591
        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);
1592
    }
1593
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1594
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1595

    
1596
    /* prepare output buffer */
1597
    c->http_error = 0;
1598
    c->buffer_ptr = c->buffer;
1599
    c->buffer_end = q;
1600
    c->state = HTTPSTATE_SEND_HEADER;
1601
    return 0;
1602
 send_error:
1603
    c->http_error = 404;
1604
    q = c->buffer;
1605
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1606
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1607
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1608
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1609
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1610
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1611
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1612

    
1613
    /* prepare output buffer */
1614
    c->buffer_ptr = c->buffer;
1615
    c->buffer_end = q;
1616
    c->state = HTTPSTATE_SEND_HEADER;
1617
    return 0;
1618
 send_status:
1619
    compute_status(c);
1620
    c->http_error = 200; /* horrible : we use this value to avoid
1621
                            going to the send data state */
1622
    c->state = HTTPSTATE_SEND_HEADER;
1623
    return 0;
1624
}
1625

    
1626
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1627
{
1628
    static const char *suffix = " kMGTP";
1629
    const char *s;
1630

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

    
1633
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1634
}
1635

    
1636
static void compute_status(HTTPContext *c)
1637
{
1638
    HTTPContext *c1;
1639
    FFStream *stream;
1640
    char *p;
1641
    time_t ti;
1642
    int i, len;
1643
    ByteIOContext *pb;
1644

    
1645
    if (url_open_dyn_buf(&pb) < 0) {
1646
        /* XXX: return an error ? */
1647
        c->buffer_ptr = c->buffer;
1648
        c->buffer_end = c->buffer;
1649
        return;
1650
    }
1651

    
1652
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1653
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1654
    url_fprintf(pb, "Pragma: no-cache\r\n");
1655
    url_fprintf(pb, "\r\n");
1656

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

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

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

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

    
1755
    stream = first_stream;
1756
    while (stream != NULL) {
1757
        if (stream->feed == stream) {
1758
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1759
            if (stream->pid) {
1760
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1761

    
1762
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1763
                {
1764
                    FILE *pid_stat;
1765
                    char ps_cmd[64];
1766

    
1767
                    /* This is somewhat linux specific I guess */
1768
                    snprintf(ps_cmd, sizeof(ps_cmd),
1769
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1770
                             stream->pid);
1771

    
1772
                    pid_stat = popen(ps_cmd, "r");
1773
                    if (pid_stat) {
1774
                        char cpuperc[10];
1775
                        char cpuused[64];
1776

    
1777
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1778
                                   cpuused) == 2) {
1779
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1780
                                         cpuperc, cpuused);
1781
                        }
1782
                        fclose(pid_stat);
1783
                    }
1784
                }
1785
#endif
1786

    
1787
                url_fprintf(pb, "<p>");
1788
            }
1789
            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");
1790

    
1791
            for (i = 0; i < stream->nb_streams; i++) {
1792
                AVStream *st = stream->streams[i];
1793
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1794
                const char *type = "unknown";
1795
                char parameters[64];
1796

    
1797
                parameters[0] = 0;
1798

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

    
1817
        }
1818
        stream = stream->next;
1819
    }
1820

    
1821
#if 0
1822
    {
1823
        float avg;
1824
        AVCodecContext *enc;
1825
        char buf[1024];
1826

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

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

    
1851
    /* connection status */
1852
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1853

    
1854
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1855
                 nb_connections, nb_max_connections);
1856

    
1857
    url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
1858
                 current_bandwidth, max_bandwidth);
1859

    
1860
    url_fprintf(pb, "<TABLE>\n");
1861
    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");
1862
    c1 = first_http_ctx;
1863
    i = 0;
1864
    while (c1 != NULL) {
1865
        int bitrate;
1866
        int j;
1867

    
1868
        bitrate = 0;
1869
        if (c1->stream) {
1870
            for (j = 0; j < c1->stream->nb_streams; j++) {
1871
                if (!c1->stream->feed)
1872
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1873
                else if (c1->feed_streams[j] >= 0)
1874
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1875
            }
1876
        }
1877

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

    
1897
    /* date */
1898
    ti = time(NULL);
1899
    p = ctime(&ti);
1900
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1901
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1902

    
1903
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1904
    c->buffer_ptr = c->pb_buffer;
1905
    c->buffer_end = c->pb_buffer + len;
1906
}
1907

    
1908
/* check if the parser needs to be opened for stream i */
1909
static void open_parser(AVFormatContext *s, int i)
1910
{
1911
    AVStream *st = s->streams[i];
1912
    AVCodec *codec;
1913

    
1914
    if (!st->codec->codec) {
1915
        codec = avcodec_find_decoder(st->codec->codec_id);
1916
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1917
            st->codec->parse_only = 1;
1918
            if (avcodec_open(st->codec, codec) < 0)
1919
                st->codec->parse_only = 0;
1920
        }
1921
    }
1922
}
1923

    
1924
static int open_input_stream(HTTPContext *c, const char *info)
1925
{
1926
    char buf[128];
1927
    char input_filename[1024];
1928
    AVFormatContext *s;
1929
    int buf_size, i, ret;
1930
    int64_t stream_pos;
1931

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

    
1960
#if 0
1961
    { time_t when = stream_pos / 1000000;
1962
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1963
    }
1964
#endif
1965

    
1966
    /* open stream */
1967
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1968
                                  buf_size, c->stream->ap_in)) < 0) {
1969
        http_log("could not open %s: %d\n", input_filename, ret);
1970
        return -1;
1971
    }
1972
    s->flags |= AVFMT_FLAG_GENPTS;
1973
    c->fmt_in = s;
1974
    av_find_stream_info(c->fmt_in);
1975

    
1976
    /* open each parser */
1977
    for(i=0;i<s->nb_streams;i++)
1978
        open_parser(s, i);
1979

    
1980
    /* choose stream as clock source (we favorize video stream if
1981
       present) for packet sending */
1982
    c->pts_stream_index = 0;
1983
    for(i=0;i<c->stream->nb_streams;i++) {
1984
        if (c->pts_stream_index == 0 &&
1985
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1986
            c->pts_stream_index = i;
1987
        }
1988
    }
1989

    
1990
#if 1
1991
    if (c->fmt_in->iformat->read_seek)
1992
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1993
#endif
1994
    /* set the start time (needed for maxtime and RTP packet timing) */
1995
    c->start_time = cur_time;
1996
    c->first_pts = AV_NOPTS_VALUE;
1997
    return 0;
1998
}
1999

    
2000
/* return the server clock (in us) */
2001
static int64_t get_server_clock(HTTPContext *c)
2002
{
2003
    /* compute current pts value from system time */
2004
    return (cur_time - c->start_time) * 1000;
2005
}
2006

    
2007
/* return the estimated time at which the current packet must be sent
2008
   (in us) */
2009
static int64_t get_packet_send_clock(HTTPContext *c)
2010
{
2011
    int bytes_left, bytes_sent, frame_bytes;
2012

    
2013
    frame_bytes = c->cur_frame_bytes;
2014
    if (frame_bytes <= 0)
2015
        return c->cur_pts;
2016
    else {
2017
        bytes_left = c->buffer_end - c->buffer_ptr;
2018
        bytes_sent = frame_bytes - bytes_left;
2019
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2020
    }
2021
}
2022

    
2023

    
2024
static int http_prepare_data(HTTPContext *c)
2025
{
2026
    int i, len, ret;
2027
    AVFormatContext *ctx;
2028

    
2029
    av_freep(&c->pb_buffer);
2030
    switch(c->state) {
2031
    case HTTPSTATE_SEND_DATA_HEADER:
2032
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2033
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
2034
                   sizeof(c->fmt_ctx.author));
2035
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2036
                   sizeof(c->fmt_ctx.comment));
2037
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2038
                   sizeof(c->fmt_ctx.copyright));
2039
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2040
                   sizeof(c->fmt_ctx.title));
2041

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

    
2054
            *st = *src;
2055
            st->priv_data = 0;
2056
            st->codec->frame_number = 0; /* XXX: should be done in
2057
                                           AVStream, not in codec */
2058
        }
2059
        /* set output format parameters */
2060
        c->fmt_ctx.oformat = c->stream->fmt;
2061
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2062

    
2063
        c->got_key_frame = 0;
2064

    
2065
        /* prepare header and save header data in a stream */
2066
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2067
            /* XXX: potential leak */
2068
            return -1;
2069
        }
2070
        c->fmt_ctx.pb->is_streamed = 1;
2071

    
2072
        /*
2073
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2074
         * Default value from FFmpeg
2075
         * Try to set it use configuration option
2076
         */
2077
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2078
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2079

    
2080
        av_set_parameters(&c->fmt_ctx, NULL);
2081
        if (av_write_header(&c->fmt_ctx) < 0) {
2082
            http_log("Error writing output header\n");
2083
            return -1;
2084
        }
2085

    
2086
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2087
        c->buffer_ptr = c->pb_buffer;
2088
        c->buffer_end = c->pb_buffer + len;
2089

    
2090
        c->state = HTTPSTATE_SEND_DATA;
2091
        c->last_packet_sent = 0;
2092
        break;
2093
    case HTTPSTATE_SEND_DATA:
2094
        /* find a new packet */
2095
        /* read a packet from the input stream */
2096
        if (c->stream->feed)
2097
            ffm_set_write_index(c->fmt_in,
2098
                                c->stream->feed->feed_write_index,
2099
                                c->stream->feed->feed_size);
2100

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

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

    
2213
                    ctx->pb->is_streamed = 1;
2214
                    if (pkt.dts != AV_NOPTS_VALUE)
2215
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2216
                    if (pkt.pts != AV_NOPTS_VALUE)
2217
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2218
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2219
                    if (av_write_frame(ctx, &pkt) < 0) {
2220
                        http_log("Error writing frame to output\n");
2221
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2222
                    }
2223

    
2224
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2225
                    c->cur_frame_bytes = len;
2226
                    c->buffer_ptr = c->pb_buffer;
2227
                    c->buffer_end = c->pb_buffer + len;
2228

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

    
2256
        c->last_packet_sent = 1;
2257
        break;
2258
    }
2259
    return 0;
2260
}
2261

    
2262
/* should convert the format at the same time */
2263
/* send data starting at c->buffer_ptr to the output connection
2264
   (either UDP or TCP connection) */
2265
static int http_send_data(HTTPContext *c)
2266
{
2267
    int len, ret;
2268

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

    
2298
                c->data_count += len;
2299
                update_datarate(&c->datarate, c->data_count);
2300
                if (c->stream)
2301
                    c->stream->bytes_served += len;
2302

    
2303
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2304
                    /* RTP packets are sent inside the RTSP TCP connection */
2305
                    ByteIOContext *pb;
2306
                    int interleaved_index, size;
2307
                    uint8_t header[4];
2308
                    HTTPContext *rtsp_c;
2309

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

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

    
2373
                c->data_count += len;
2374
                update_datarate(&c->datarate, c->data_count);
2375
                if (c->stream)
2376
                    c->stream->bytes_served += len;
2377
                break;
2378
            }
2379
        }
2380
    } /* for(;;) */
2381
    return 0;
2382
}
2383

    
2384
static int http_start_receive_data(HTTPContext *c)
2385
{
2386
    int fd;
2387

    
2388
    if (c->stream->feed_opened)
2389
        return -1;
2390

    
2391
    /* Don't permit writing to this one */
2392
    if (c->stream->readonly)
2393
        return -1;
2394

    
2395
    /* open feed */
2396
    fd = open(c->stream->feed_filename, O_RDWR);
2397
    if (fd < 0) {
2398
        http_log("Error opening feeder file: %s\n", strerror(errno));
2399
        return -1;
2400
    }
2401
    c->feed_fd = fd;
2402

    
2403
    c->stream->feed_write_index = ffm_read_write_index(fd);
2404
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2405
    lseek(fd, 0, SEEK_SET);
2406

    
2407
    /* init buffer input */
2408
    c->buffer_ptr = c->buffer;
2409
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2410
    c->stream->feed_opened = 1;
2411
    return 0;
2412
}
2413

    
2414
static int http_receive_data(HTTPContext *c)
2415
{
2416
    HTTPContext *c1;
2417

    
2418
    if (c->buffer_end > c->buffer_ptr) {
2419
        int len;
2420

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

    
2437
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2438
        if (c->buffer[0] != 'f' ||
2439
            c->buffer[1] != 'm') {
2440
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2441
            goto fail;
2442
        }
2443
    }
2444

    
2445
    if (c->buffer_ptr >= c->buffer_end) {
2446
        FFStream *feed = c->stream;
2447
        /* a packet has been received : write it in the store, except
2448
           if header */
2449
        if (c->data_count > FFM_PACKET_SIZE) {
2450

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

    
2459
            feed->feed_write_index += FFM_PACKET_SIZE;
2460
            /* update file size */
2461
            if (feed->feed_write_index > c->stream->feed_size)
2462
                feed->feed_size = feed->feed_write_index;
2463

    
2464
            /* handle wrap around if max file size reached */
2465
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2466
                feed->feed_write_index = FFM_PACKET_SIZE;
2467

    
2468
            /* write index */
2469
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2470

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

    
2484
            /* use feed output format name to find corresponding input format */
2485
            fmt_in = av_find_input_format(feed->fmt->name);
2486
            if (!fmt_in)
2487
                goto fail;
2488

    
2489
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2490
            pb->is_streamed = 1;
2491

    
2492
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2493
                av_free(pb);
2494
                goto fail;
2495
            }
2496

    
2497
            /* Now we have the actual streams */
2498
            if (s->nb_streams != feed->nb_streams) {
2499
                av_close_input_stream(s);
2500
                av_free(pb);
2501
                goto fail;
2502
            }
2503

    
2504
            for (i = 0; i < s->nb_streams; i++) {
2505
                AVStream *fst = feed->streams[i];
2506
                AVStream *st = s->streams[i];
2507
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2508
                if (fst->codec->extradata_size) {
2509
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2510
                    if (!fst->codec->extradata)
2511
                        goto fail;
2512
                    memcpy(fst->codec->extradata, st->codec->extradata,
2513
                           fst->codec->extradata_size);
2514
                }
2515
            }
2516

    
2517
            av_close_input_stream(s);
2518
            av_free(pb);
2519
        }
2520
        c->buffer_ptr = c->buffer;
2521
    }
2522

    
2523
    return 0;
2524
 fail:
2525
    c->stream->feed_opened = 0;
2526
    close(c->feed_fd);
2527
    /* wake up any waiting connections to stop waiting for feed */
2528
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2529
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2530
            c1->stream->feed == c->stream->feed)
2531
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2532
    }
2533
    return -1;
2534
}
2535

    
2536
/********************************************************************/
2537
/* RTSP handling */
2538

    
2539
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2540
{
2541
    const char *str;
2542
    time_t ti;
2543
    char *p;
2544
    char buf2[32];
2545

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

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

    
2588
    /* output GMT time */
2589
    ti = time(NULL);
2590
    p = ctime(&ti);
2591
    strcpy(buf2, p);
2592
    p = buf2 + strlen(p) - 1;
2593
    if (*p == '\n')
2594
        *p = '\0';
2595
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2596
}
2597

    
2598
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2599
{
2600
    rtsp_reply_header(c, error_number);
2601
    url_fprintf(c->pb, "\r\n");
2602
}
2603

    
2604
static int rtsp_parse_request(HTTPContext *c)
2605
{
2606
    const char *p, *p1, *p2;
2607
    char cmd[32];
2608
    char url[1024];
2609
    char protocol[32];
2610
    char line[1024];
2611
    int len;
2612
    RTSPHeader header1, *header = &header1;
2613

    
2614
    c->buffer_ptr[0] = '\0';
2615
    p = c->buffer;
2616

    
2617
    get_word(cmd, sizeof(cmd), &p);
2618
    get_word(url, sizeof(url), &p);
2619
    get_word(protocol, sizeof(protocol), &p);
2620

    
2621
    av_strlcpy(c->method, cmd, sizeof(c->method));
2622
    av_strlcpy(c->url, url, sizeof(c->url));
2623
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2624

    
2625
    if (url_open_dyn_buf(&c->pb) < 0) {
2626
        /* XXX: cannot do more */
2627
        c->pb = NULL; /* safety */
2628
        return -1;
2629
    }
2630

    
2631
    /* check version name */
2632
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2633
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2634
        goto the_end;
2635
    }
2636

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

    
2663
    /* handle sequence number */
2664
    c->seq = header->seq;
2665

    
2666
    if (!strcmp(cmd, "DESCRIBE"))
2667
        rtsp_cmd_describe(c, url);
2668
    else if (!strcmp(cmd, "OPTIONS"))
2669
        rtsp_cmd_options(c, url);
2670
    else if (!strcmp(cmd, "SETUP"))
2671
        rtsp_cmd_setup(c, url, header);
2672
    else if (!strcmp(cmd, "PLAY"))
2673
        rtsp_cmd_play(c, url, header);
2674
    else if (!strcmp(cmd, "PAUSE"))
2675
        rtsp_cmd_pause(c, url, header);
2676
    else if (!strcmp(cmd, "TEARDOWN"))
2677
        rtsp_cmd_teardown(c, url, header);
2678
    else
2679
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2680

    
2681
 the_end:
2682
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2683
    c->pb = NULL; /* safety */
2684
    if (len < 0) {
2685
        /* XXX: cannot do more */
2686
        return -1;
2687
    }
2688
    c->buffer_ptr = c->pb_buffer;
2689
    c->buffer_end = c->pb_buffer + len;
2690
    c->state = RTSPSTATE_SEND_REPLY;
2691
    return 0;
2692
}
2693

    
2694
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2695
                                   struct in_addr my_ip)
2696
{
2697
    AVFormatContext *avc;
2698
    AVStream avs[MAX_STREAMS];
2699
    int i;
2700

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

    
2717
    for(i = 0; i < stream->nb_streams; i++) {
2718
        avc->streams[i] = &avs[i];
2719
        avc->streams[i]->codec = stream->streams[i]->codec;
2720
    }
2721
    *pbuffer = av_mallocz(2048);
2722
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2723
    av_free(avc);
2724

    
2725
    return strlen(*pbuffer);
2726
}
2727

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

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

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

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

    
2763
 found:
2764
    /* prepare the media description in sdp format */
2765

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

    
2781
static HTTPContext *find_rtp_session(const char *session_id)
2782
{
2783
    HTTPContext *c;
2784

    
2785
    if (session_id[0] == '\0')
2786
        return NULL;
2787

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2913
    /* setup stream */
2914
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2915
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2916
        return;
2917
    }
2918

    
2919
    /* now everything is OK, so we can send the connection parameters */
2920
    rtsp_reply_header(c, RTSP_STATUS_OK);
2921
    /* session ID */
2922
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2923

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

    
2943

    
2944
    url_fprintf(c->pb, "\r\n");
2945
}
2946

    
2947

    
2948
/* find an rtp connection by using the session ID. Check consistency
2949
   with filename */
2950
static HTTPContext *find_rtp_session_with_url(const char *url,
2951
                                              const char *session_id)
2952
{
2953
    HTTPContext *rtp_c;
2954
    char path1[1024];
2955
    const char *path;
2956
    char buf[1024];
2957
    int s;
2958

    
2959
    rtp_c = find_rtp_session(session_id);
2960
    if (!rtp_c)
2961
        return NULL;
2962

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

    
2980
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2981
{
2982
    HTTPContext *rtp_c;
2983

    
2984
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2985
    if (!rtp_c) {
2986
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2987
        return;
2988
    }
2989

    
2990
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2991
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2992
        rtp_c->state != HTTPSTATE_READY) {
2993
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2994
        return;
2995
    }
2996

    
2997
#if 0
2998
    /* XXX: seek in stream */
2999
    if (h->range_start != AV_NOPTS_VALUE) {
3000
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3001
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3002
    }
3003
#endif
3004

    
3005
    rtp_c->state = HTTPSTATE_SEND_DATA;
3006

    
3007
    /* now everything is OK, so we can send the connection parameters */
3008
    rtsp_reply_header(c, RTSP_STATUS_OK);
3009
    /* session ID */
3010
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3011
    url_fprintf(c->pb, "\r\n");
3012
}
3013

    
3014
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3015
{
3016
    HTTPContext *rtp_c;
3017

    
3018
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3019
    if (!rtp_c) {
3020
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3021
        return;
3022
    }
3023

    
3024
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3025
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3026
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3027
        return;
3028
    }
3029

    
3030
    rtp_c->state = HTTPSTATE_READY;
3031
    rtp_c->first_pts = AV_NOPTS_VALUE;
3032
    /* now everything is OK, so we can send the connection parameters */
3033
    rtsp_reply_header(c, RTSP_STATUS_OK);
3034
    /* session ID */
3035
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3036
    url_fprintf(c->pb, "\r\n");
3037
}
3038

    
3039
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3040
{
3041
    HTTPContext *rtp_c;
3042
    char session_id[32];
3043

    
3044
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3045
    if (!rtp_c) {
3046
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3047
        return;
3048
    }
3049

    
3050
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3051

    
3052
    /* abort the session */
3053
    close_connection(rtp_c);
3054

    
3055
    /* now everything is OK, so we can send the connection parameters */
3056
    rtsp_reply_header(c, RTSP_STATUS_OK);
3057
    /* session ID */
3058
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3059
    url_fprintf(c->pb, "\r\n");
3060
}
3061

    
3062

    
3063
/********************************************************************/
3064
/* RTP handling */
3065

    
3066
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3067
                                       FFStream *stream, const char *session_id,
3068
                                       enum RTSPProtocol rtp_protocol)
3069
{
3070
    HTTPContext *c = NULL;
3071
    const char *proto_str;
3072

    
3073
    /* XXX: should output a warning page when coming
3074
       close to the connection limit */
3075
    if (nb_connections >= nb_max_connections)
3076
        goto fail;
3077

    
3078
    /* add a new connection */
3079
    c = av_mallocz(sizeof(HTTPContext));
3080
    if (!c)
3081
        goto fail;
3082

    
3083
    c->fd = -1;
3084
    c->poll_entry = NULL;
3085
    c->from_addr = *from_addr;
3086
    c->buffer_size = IOBUFFER_INIT_SIZE;
3087
    c->buffer = av_malloc(c->buffer_size);
3088
    if (!c->buffer)
3089
        goto fail;
3090
    nb_connections++;
3091
    c->stream = stream;
3092
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3093
    c->state = HTTPSTATE_READY;
3094
    c->is_packetized = 1;
3095
    c->rtp_protocol = rtp_protocol;
3096

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

    
3115
    current_bandwidth += stream->bandwidth;
3116

    
3117
    c->next = first_http_ctx;
3118
    first_http_ctx = c;
3119
    return c;
3120

    
3121
 fail:
3122
    if (c) {
3123
        av_free(c->buffer);
3124
        av_free(c);
3125
    }
3126
    return NULL;
3127
}
3128

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

    
3143
    /* now we can open the relevant output stream */
3144
    ctx = av_alloc_format_context();
3145
    if (!ctx)
3146
        return -1;
3147
    ctx->oformat = guess_format("rtp", NULL, NULL);
3148

    
3149
    st = av_mallocz(sizeof(AVStream));
3150
    if (!st)
3151
        goto fail;
3152
    st->codec= avcodec_alloc_context();
3153
    ctx->nb_streams = 1;
3154
    ctx->streams[0] = st;
3155

    
3156
    if (!c->stream->feed ||
3157
        c->stream->feed == c->stream)
3158
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3159
    else
3160
        memcpy(st,
3161
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3162
               sizeof(AVStream));
3163
    st->priv_data = NULL;
3164

    
3165
    /* build destination RTP address */
3166
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3167

    
3168
    switch(c->rtp_protocol) {
3169
    case RTSP_PROTOCOL_RTP_UDP:
3170
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3171
        /* RTP/UDP case */
3172

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

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

    
3201
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3202
             ipaddr, ntohs(dest_addr->sin_port),
3203
             c->stream->filename, stream_index, c->protocol);
3204

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

    
3221
    c->rtp_ctx[stream_index] = ctx;
3222
    return 0;
3223
}
3224

    
3225
/********************************************************************/
3226
/* ffserver initialization */
3227

    
3228
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3229
{
3230
    AVStream *fst;
3231

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

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

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

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

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

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

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

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

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

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

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

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

    
3388
                for(i=0;i<infile->nb_streams;i++)
3389
                    add_av_stream1(stream, infile->streams[i]->codec);
3390

    
3391
                av_close_input_file(infile);
3392
            }
3393
        }
3394
    }
3395
}
3396

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

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

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

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

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

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

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

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

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

    
3489
                av_close_input_file(s);
3490
            } else
3491
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3492
                        feed->feed_filename);
3493

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

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

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

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

    
3548
        close(fd);
3549
    }
3550
}
3551

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

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

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

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

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

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

    
3647
        if (!av->nsse_weight)
3648
            av->nsse_weight = 8;
3649

    
3650
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3651
        av->me_method = ME_EPZS;
3652
        av->rc_buffer_aggressivity = 1.0;
3653

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

    
3665
        if (av->rc_max_rate && !av->rc_buffer_size) {
3666
            av->rc_buffer_size = av->rc_max_rate;
3667
        }
3668

    
3669

    
3670
        break;
3671
    default:
3672
        abort();
3673
    }
3674

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

    
3683
static int opt_audio_codec(const char *arg)
3684
{
3685
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3686

    
3687
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3688
        return CODEC_ID_NONE;
3689

    
3690
    return p->id;
3691
}
3692

    
3693
static int opt_video_codec(const char *arg)
3694
{
3695
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3696

    
3697
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3698
        return CODEC_ID_NONE;
3699

    
3700
    return p->id;
3701
}
3702

    
3703
/* simplistic plugin support */
3704

    
3705
#ifdef HAVE_DLOPEN
3706
static void load_module(const char *filename)
3707
{
3708
    void *dll;
3709
    void (*init_func)(void);
3710
    dll = dlopen(filename, RTLD_NOW);
3711
    if (!dll) {
3712
        fprintf(stderr, "Could not load module '%s' - %s\n",
3713
                filename, dlerror());
3714
        return;
3715
    }
3716

    
3717
    init_func = dlsym(dll, "ffserver_module_init");
3718
    if (!init_func) {
3719
        fprintf(stderr,
3720
                "%s: init function 'ffserver_module_init()' not found\n",
3721
                filename);
3722
        dlclose(dll);
3723
    }
3724

    
3725
    init_func();
3726
}
3727
#endif
3728

    
3729
static int opt_default(const char *opt, const char *arg,
3730
                       AVCodecContext *avctx, int type)
3731
{
3732
    const AVOption *o  = NULL;
3733
    const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
3734
    if(o2)
3735
        o = av_set_string(avctx, opt, arg);
3736
    if(!o)
3737
        return -1;
3738
    return 0;
3739
}
3740

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

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

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

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

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

    
3856
                get_arg(feed->filename, sizeof(feed->filename), &p);
3857
                q = strrchr(feed->filename, '>');
3858
                if (*q)
3859
                    *q = '\0';
3860
                feed->fmt = guess_format("ffm", NULL, NULL);
3861
                /* defaut feed file */
3862
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3863
                         "/tmp/%s.ffm", feed->filename);
3864
                feed->feed_max_size = 5 * 1024 * 1024;
3865
                feed->is_feed = 1;
3866
                feed->feed = feed; /* self feeding :-) */
3867
            }
3868
        } else if (!strcasecmp(cmd, "Launch")) {
3869
            if (feed) {
3870
                int i;
3871

    
3872
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3873

    
3874
                for (i = 0; i < 62; i++) {
3875
                    get_arg(arg, sizeof(arg), &p);
3876
                    if (!arg[0])
3877
                        break;
3878

    
3879
                    feed->child_argv[i] = av_strdup(arg);
3880
                }
3881

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

    
3884
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3885
                    "http://%s:%d/%s",
3886
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3887
                    inet_ntoa(my_http_addr.sin_addr),
3888
                    ntohs(my_http_addr.sin_port), feed->filename);
3889
            }
3890
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3891
            if (feed) {
3892
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3893
                feed->readonly = 1;
3894
            } else if (stream) {
3895
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3896
            }
3897
        } else if (!strcasecmp(cmd, "File")) {
3898
            if (feed) {
3899
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3900
            } else if (stream)
3901
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3902
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3903
            if (feed) {
3904
                char *p1;
3905
                double fsize;
3906

    
3907
                get_arg(arg, sizeof(arg), &p);
3908
                p1 = arg;
3909
                fsize = strtod(p1, &p1);
3910
                switch(toupper(*p1)) {
3911
                case 'K':
3912
                    fsize *= 1024;
3913
                    break;
3914
                case 'M':
3915
                    fsize *= 1024 * 1024;
3916
                    break;
3917
                case 'G':
3918
                    fsize *= 1024 * 1024 * 1024;
3919
                    break;
3920
                }
3921
                feed->feed_max_size = (int64_t)fsize;
3922
            }
3923
        } else if (!strcasecmp(cmd, "</Feed>")) {
3924
            if (!feed) {
3925
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3926
                        filename, line_num);
3927
                errors++;
3928
            }
3929
            feed = NULL;
3930
        } else if (!strcasecmp(cmd, "<Stream")) {
3931
            /*********************************************/
3932
            /* Stream related options */
3933
            char *q;
3934
            if (stream || feed) {
3935
                fprintf(stderr, "%s:%d: Already in a tag\n",
3936
                        filename, line_num);
3937
            } else {
3938
                const AVClass *class;
3939
                stream = av_mallocz(sizeof(FFStream));
3940
                *last_stream = stream;
3941
                last_stream = &stream->next;
3942

    
3943
                get_arg(stream->filename, sizeof(stream->filename), &p);
3944
                q = strrchr(stream->filename, '>');
3945
                if (*q)
3946
                    *q = '\0';
3947
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3948
                /* fetch avclass so AVOption works
3949
                 * FIXME try to use avcodec_get_context_defaults2
3950
                 * without changing defaults too much */
3951
                avcodec_get_context_defaults(&video_enc);
3952
                class = video_enc.av_class;
3953
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3954
                memset(&video_enc, 0, sizeof(AVCodecContext));
3955
                audio_enc.av_class = class;
3956
                video_enc.av_class = class;
3957
                audio_id = CODEC_ID_NONE;
3958
                video_id = CODEC_ID_NONE;
3959
                if (stream->fmt) {
3960
                    audio_id = stream->fmt->audio_codec;
3961
                    video_id = stream->fmt->video_codec;
3962
                }
3963
            }
3964
        } else if (!strcasecmp(cmd, "Feed")) {
3965
            get_arg(arg, sizeof(arg), &p);
3966
            if (stream) {
3967
                FFStream *sfeed;
3968

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

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

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

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

    
4254
            get_arg(arg, sizeof(arg), &p);
4255

    
4256
            if (resolve_host(&acl.first, arg) != 0) {
4257
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4258
                        filename, line_num, arg);
4259
                errors++;
4260
            } else
4261
                acl.last = acl.first;
4262

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

    
4265
            if (arg[0]) {
4266
                if (resolve_host(&acl.last, arg) != 0) {
4267
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4268
                            filename, line_num, arg);
4269
                    errors++;
4270
                }
4271
            }
4272

    
4273
            if (!errors) {
4274
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4275
                IPAddressACL **naclp = 0;
4276

    
4277
                acl.next = 0;
4278
                *nacl = acl;
4279

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

    
4290
                if (naclp) {
4291
                    while (*naclp)
4292
                        naclp = &(*naclp)->next;
4293

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

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

    
4395
    fclose(f);
4396
    if (errors)
4397
        return -1;
4398
    else
4399
        return 0;
4400
}
4401

    
4402
static void handle_child_exit(int sig)
4403
{
4404
    pid_t pid;
4405
    int status;
4406

    
4407
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4408
        FFStream *feed;
4409

    
4410
        for (feed = first_feed; feed; feed = feed->next) {
4411
            if (feed->pid == pid) {
4412
                int uptime = time(0) - feed->pid_start;
4413

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

    
4417
                if (uptime < 30)
4418
                    /* Turn off any more restarts */
4419
                    feed->child_argv = 0;
4420
            }
4421
        }
4422
    }
4423

    
4424
    need_to_start_children = 1;
4425
}
4426

    
4427
static void opt_debug()
4428
{
4429
    ffserver_debug = 1;
4430
    ffserver_daemon = 0;
4431
    logfilename[0] = '-';
4432
}
4433

    
4434
static void opt_show_help(void)
4435
{
4436
    printf("usage: ffserver [options]\n"
4437
           "Hyper fast multi format Audio/Video streaming server\n");
4438
    printf("\n");
4439
    show_help_options(options, "Main options:\n", 0, 0);
4440
}
4441

    
4442
static const OptionDef options[] = {
4443
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4444
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4445
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4446
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4447
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4448
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4449
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4450
    { NULL },
4451
};
4452

    
4453
int main(int argc, char **argv)
4454
{
4455
    struct sigaction sigact;
4456

    
4457
    av_register_all();
4458

    
4459
    show_banner();
4460

    
4461
    config_filename = "/etc/ffserver.conf";
4462

    
4463
    my_program_name = argv[0];
4464
    my_program_dir = getcwd(0, 0);
4465
    ffserver_daemon = 1;
4466

    
4467
    parse_options(argc, argv, options, NULL);
4468

    
4469
    unsetenv("http_proxy");             /* Kill the http_proxy */
4470

    
4471
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4472

    
4473
    memset(&sigact, 0, sizeof(sigact));
4474
    sigact.sa_handler = handle_child_exit;
4475
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4476
    sigaction(SIGCHLD, &sigact, 0);
4477

    
4478
    if (parse_ffconfig(config_filename) < 0) {
4479
        fprintf(stderr, "Incorrect config file - exiting.\n");
4480
        exit(1);
4481
    }
4482

    
4483
    /* open log file if needed */
4484
    if (logfilename[0] != '\0') {
4485
        if (!strcmp(logfilename, "-"))
4486
            logfile = stderr;
4487
        else
4488
            logfile = fopen(logfilename, "a");
4489
        av_log_set_callback(http_av_log);
4490
    }
4491

    
4492
    build_file_streams();
4493

    
4494
    build_feed_streams();
4495

    
4496
    compute_bandwidth();
4497

    
4498
    /* put the process in background and detach it from its TTY */
4499
    if (ffserver_daemon) {
4500
        int pid;
4501

    
4502
        pid = fork();
4503
        if (pid < 0) {
4504
            perror("fork");
4505
            exit(1);
4506
        } else if (pid > 0) {
4507
            /* parent : exit */
4508
            exit(0);
4509
        } else {
4510
            /* child */
4511
            setsid();
4512
            close(0);
4513
            open("/dev/null", O_RDWR);
4514
            if (strcmp(logfilename, "-") != 0) {
4515
                close(1);
4516
                dup(0);
4517
            }
4518
            close(2);
4519
            dup(0);
4520
        }
4521
    }
4522

    
4523
    /* signal init */
4524
    signal(SIGPIPE, SIG_IGN);
4525

    
4526
    if (ffserver_daemon)
4527
        chdir("/");
4528

    
4529
    if (http_server() < 0) {
4530
        http_log("Could not start server\n");
4531
        exit(1);
4532
    }
4533

    
4534
    return 0;
4535
}