Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3a74415d

History | View | Annotate | Download (152 KB)

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

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

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

    
50
#undef exit
51

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

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

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

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

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

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

    
86
#define IOBUFFER_INIT_SIZE 8192
87

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

    
92
#define SYNC_TIMEOUT (10 * 1000)
93

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

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

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

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

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

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

    
162
static AVFrame dummy_frame;
163

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

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

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

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

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

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

    
237
struct sockaddr_in my_http_addr;
238
struct sockaddr_in my_rtsp_addr;
239

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

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

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

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

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

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

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

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

    
286
static int nb_max_connections;
287
static int nb_connections;
288

    
289
static int max_bandwidth;
290
static int current_bandwidth;
291

    
292
static int64_t cur_time;           // Making this global saves on passing it around everywhere
293

    
294
static AVRandomState random_state;
295

    
296
static FILE *logfile = NULL;
297

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

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

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

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

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

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

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

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

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

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

    
361

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

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

    
371
            feed->pid = fork();
372

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

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

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

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

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

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

    
410
                signal(SIGPIPE, SIG_DFL);
411

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

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

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

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

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

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

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

    
449
    return server_fd;
450
}
451

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

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

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

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

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

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

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

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

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

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

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

    
524
    start_children(first_feed);
525

    
526
    first_http_ctx = NULL;
527
    nb_connections = 0;
528

    
529
    start_multicast();
530

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

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

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

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

    
599
        cur_time = av_gettime() / 1000;
600

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

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

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

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

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

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

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

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

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

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

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

    
679
    start_wait_request(c, is_rtsp);
680

    
681
    return;
682

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

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

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

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

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

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

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

    
747
    ctx = &c->fmt_ctx;
748

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
967
                q += 20;
968

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

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

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

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

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

    
994
        p++;
995
    }
996

    
997
    return 0;
998
}
999

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

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

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

    
1016
        /* Potential stream */
1017

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

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

    
1035
    return best;
1036
}
1037

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

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

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

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

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

    
1073
    return action_required;
1074
}
1075

    
1076

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1232
        p++;
1233
    }
1234

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

    
1254
    // "redirect" / request to index.html
1255
    if (!strlen(filename))
1256
        pstrcpy(filename, sizeof(filename) - 1, "index.html");
1257

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

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

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

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

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

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

    
1307
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1308
        current_bandwidth += stream->bandwidth;
1309
    }
1310

    
1311
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1312
        c->http_error = 200;
1313
        q = c->buffer;
1314
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1315
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1316
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1317
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1318
        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");
1319
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1320
            current_bandwidth, max_bandwidth);
1321
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1322

    
1323
        /* prepare output buffer */
1324
        c->buffer_ptr = c->buffer;
1325
        c->buffer_end = q;
1326
        c->state = HTTPSTATE_SEND_HEADER;
1327
        return 0;
1328
    }
1329

    
1330
    if (redir_type != REDIR_NONE) {
1331
        char *hostinfo = 0;
1332

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

    
1342
            p++;
1343
        }
1344

    
1345
        if (hostinfo) {
1346
            char *eoh;
1347
            char hostbuf[260];
1348

    
1349
            while (isspace(*hostinfo))
1350
                hostinfo++;
1351

    
1352
            eoh = strchr(hostinfo, '\n');
1353
            if (eoh) {
1354
                if (eoh[-1] == '\r')
1355
                    eoh--;
1356

    
1357
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1358
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1359
                    hostbuf[eoh - hostinfo] = 0;
1360

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

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

    
1417
                            len = sizeof(my_addr);
1418
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1419

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

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

    
1446
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1447
        goto send_error;
1448
    }
1449

    
1450
    stream->conns_served++;
1451

    
1452
    /* XXX: add there authenticate and IP match */
1453

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

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

    
1475
                p++;
1476
            }
1477

    
1478
            if (logline) {
1479
                char *eol = strchr(logline, '\n');
1480

    
1481
                logline += 17;
1482

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

    
1491
#ifdef DEBUG_WMP
1492
            http_log("\nGot request:\n%s\n", c->buffer);
1493
#endif
1494

    
1495
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1496
                HTTPContext *wmpc;
1497

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

    
1504
                if (wmpc) {
1505
                    if (modify_current_stream(wmpc, ratebuf)) {
1506
                        wmpc->switch_pending = 1;
1507
                    }
1508
                }
1509
            }
1510

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

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

    
1530
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1531
        goto send_stats;
1532

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

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

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

    
1551
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1552

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

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

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

    
1588
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1589
{
1590
    static const char *suffix = " kMGTP";
1591
    const char *s;
1592

    
1593
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1594
    }
1595

    
1596
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1597
}
1598

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

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

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

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

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

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

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

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

    
1728
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1729
                {
1730
                    FILE *pid_stat;
1731
                    char ps_cmd[64];
1732

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

    
1738
                    pid_stat = popen(ps_cmd, "r");
1739
                    if (pid_stat) {
1740
                        char cpuperc[10];
1741
                        char cpuused[64];
1742

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

    
1753
                url_fprintf(pb, "<p>");
1754
            }
1755
            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");
1756

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

    
1763
                parameters[0] = 0;
1764

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

    
1783
        }
1784
        stream = stream->next;
1785
    }
1786

    
1787
#if 0
1788
    {
1789
        float avg;
1790
        AVCodecContext *enc;
1791
        char buf[1024];
1792

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

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

    
1817
    /* connection status */
1818
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1819

    
1820
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1821
                 nb_connections, nb_max_connections);
1822

    
1823
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1824
                 current_bandwidth, max_bandwidth);
1825

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

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

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

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

    
1872
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1873
    c->buffer_ptr = c->pb_buffer;
1874
    c->buffer_end = c->pb_buffer + len;
1875
}
1876

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

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

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

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

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

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

    
1942
    /* open each parser */
1943
    for(i=0;i<s->nb_streams;i++)
1944
        open_parser(s, i);
1945

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

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

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

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

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

    
1990

    
1991
static int http_prepare_data(HTTPContext *c)
1992
{
1993
    int i, len, ret;
1994
    AVFormatContext *ctx;
1995

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

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

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

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

    
2043
        av_set_parameters(&c->fmt_ctx, NULL);
2044
        if (av_write_header(&c->fmt_ctx) < 0)
2045
            return -1;
2046

    
2047
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2048
        c->buffer_ptr = c->pb_buffer;
2049
        c->buffer_end = c->pb_buffer + len;
2050

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

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

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

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

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

    
2198
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2199
                        c->cur_frame_bytes = len;
2200
                        c->buffer_ptr = c->pb_buffer;
2201
                        c->buffer_end = c->pb_buffer + len;
2202

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

    
2228
        c->last_packet_sent = 1;
2229
        break;
2230
    }
2231
    return 0;
2232
}
2233

    
2234
/* should convert the format at the same time */
2235
/* send data starting at c->buffer_ptr to the output connection
2236
   (either UDP or TCP connection) */
2237
static int http_send_data(HTTPContext *c)
2238
{
2239
    int len, ret;
2240

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

    
2271
                c->data_count += len;
2272
                update_datarate(&c->datarate, c->data_count);
2273
                if (c->stream)
2274
                    c->stream->bytes_served += len;
2275

    
2276
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2277
                    /* RTP packets are sent inside the RTSP TCP connection */
2278
                    ByteIOContext pb1, *pb = &pb1;
2279
                    int interleaved_index, size;
2280
                    uint8_t header[4];
2281
                    HTTPContext *rtsp_c;
2282

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

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

    
2360
static int http_start_receive_data(HTTPContext *c)
2361
{
2362
    int fd;
2363

    
2364
    if (c->stream->feed_opened)
2365
        return -1;
2366

    
2367
    /* Don't permit writing to this one */
2368
    if (c->stream->readonly)
2369
        return -1;
2370

    
2371
    /* open feed */
2372
    fd = open(c->stream->feed_filename, O_RDWR);
2373
    if (fd < 0)
2374
        return -1;
2375
    c->feed_fd = fd;
2376

    
2377
    c->stream->feed_write_index = ffm_read_write_index(fd);
2378
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2379
    lseek(fd, 0, SEEK_SET);
2380

    
2381
    /* init buffer input */
2382
    c->buffer_ptr = c->buffer;
2383
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2384
    c->stream->feed_opened = 1;
2385
    return 0;
2386
}
2387

    
2388
static int http_receive_data(HTTPContext *c)
2389
{
2390
    HTTPContext *c1;
2391

    
2392
    if (c->buffer_end > c->buffer_ptr) {
2393
        int len;
2394

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

    
2411
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2412
        if (c->buffer[0] != 'f' ||
2413
            c->buffer[1] != 'm') {
2414
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2415
            goto fail;
2416
        }
2417
    }
2418

    
2419
    if (c->buffer_ptr >= c->buffer_end) {
2420
        FFStream *feed = c->stream;
2421
        /* a packet has been received : write it in the store, except
2422
           if header */
2423
        if (c->data_count > FFM_PACKET_SIZE) {
2424

    
2425
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2426
            /* XXX: use llseek or url_seek */
2427
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2428
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2429

    
2430
            feed->feed_write_index += FFM_PACKET_SIZE;
2431
            /* update file size */
2432
            if (feed->feed_write_index > c->stream->feed_size)
2433
                feed->feed_size = feed->feed_write_index;
2434

    
2435
            /* handle wrap around if max file size reached */
2436
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2437
                feed->feed_write_index = FFM_PACKET_SIZE;
2438

    
2439
            /* write index */
2440
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2441

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

    
2456
            memset(&s, 0, sizeof(s));
2457

    
2458
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2459
            pb->buf_end = c->buffer_end;        /* ?? */
2460
            pb->is_streamed = 1;
2461

    
2462
            /* use feed output format name to find corresponding input format */
2463
            fmt_in = av_find_input_format(feed->fmt->name);
2464
            if (!fmt_in)
2465
                goto fail;
2466

    
2467
            if (fmt_in->priv_data_size > 0) {
2468
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2469
                if (!s.priv_data)
2470
                    goto fail;
2471
            } else
2472
                s.priv_data = NULL;
2473

    
2474
            if (fmt_in->read_header(&s, 0) < 0) {
2475
                av_freep(&s.priv_data);
2476
                goto fail;
2477
            }
2478

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

    
2493
    return 0;
2494
 fail:
2495
    c->stream->feed_opened = 0;
2496
    close(c->feed_fd);
2497
    return -1;
2498
}
2499

    
2500
/********************************************************************/
2501
/* RTSP handling */
2502

    
2503
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2504
{
2505
    const char *str;
2506
    time_t ti;
2507
    char *p;
2508
    char buf2[32];
2509

    
2510
    switch(error_number) {
2511
    case RTSP_STATUS_OK:
2512
        str = "OK";
2513
        break;
2514
    case RTSP_STATUS_METHOD:
2515
        str = "Method Not Allowed";
2516
        break;
2517
    case RTSP_STATUS_BANDWIDTH:
2518
        str = "Not Enough Bandwidth";
2519
        break;
2520
    case RTSP_STATUS_SESSION:
2521
        str = "Session Not Found";
2522
        break;
2523
    case RTSP_STATUS_STATE:
2524
        str = "Method Not Valid in This State";
2525
        break;
2526
    case RTSP_STATUS_AGGREGATE:
2527
        str = "Aggregate operation not allowed";
2528
        break;
2529
    case RTSP_STATUS_ONLY_AGGREGATE:
2530
        str = "Only aggregate operation allowed";
2531
        break;
2532
    case RTSP_STATUS_TRANSPORT:
2533
        str = "Unsupported transport";
2534
        break;
2535
    case RTSP_STATUS_INTERNAL:
2536
        str = "Internal Server Error";
2537
        break;
2538
    case RTSP_STATUS_SERVICE:
2539
        str = "Service Unavailable";
2540
        break;
2541
    case RTSP_STATUS_VERSION:
2542
        str = "RTSP Version not supported";
2543
        break;
2544
    default:
2545
        str = "Unknown Error";
2546
        break;
2547
    }
2548

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

    
2552
    /* output GMT time */
2553
    ti = time(NULL);
2554
    p = ctime(&ti);
2555
    strcpy(buf2, p);
2556
    p = buf2 + strlen(p) - 1;
2557
    if (*p == '\n')
2558
        *p = '\0';
2559
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2560
}
2561

    
2562
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2563
{
2564
    rtsp_reply_header(c, error_number);
2565
    url_fprintf(c->pb, "\r\n");
2566
}
2567

    
2568
static int rtsp_parse_request(HTTPContext *c)
2569
{
2570
    const char *p, *p1, *p2;
2571
    char cmd[32];
2572
    char url[1024];
2573
    char protocol[32];
2574
    char line[1024];
2575
    ByteIOContext pb1;
2576
    int len;
2577
    RTSPHeader header1, *header = &header1;
2578

    
2579
    c->buffer_ptr[0] = '\0';
2580
    p = c->buffer;
2581

    
2582
    get_word(cmd, sizeof(cmd), &p);
2583
    get_word(url, sizeof(url), &p);
2584
    get_word(protocol, sizeof(protocol), &p);
2585

    
2586
    pstrcpy(c->method, sizeof(c->method), cmd);
2587
    pstrcpy(c->url, sizeof(c->url), url);
2588
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2589

    
2590
    c->pb = &pb1;
2591
    if (url_open_dyn_buf(c->pb) < 0) {
2592
        /* XXX: cannot do more */
2593
        c->pb = NULL; /* safety */
2594
        return -1;
2595
    }
2596

    
2597
    /* check version name */
2598
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2599
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2600
        goto the_end;
2601
    }
2602

    
2603
    /* parse each header line */
2604
    memset(header, 0, sizeof(RTSPHeader));
2605
    /* skip to next line */
2606
    while (*p != '\n' && *p != '\0')
2607
        p++;
2608
    if (*p == '\n')
2609
        p++;
2610
    while (*p != '\0') {
2611
        p1 = strchr(p, '\n');
2612
        if (!p1)
2613
            break;
2614
        p2 = p1;
2615
        if (p2 > p && p2[-1] == '\r')
2616
            p2--;
2617
        /* skip empty line */
2618
        if (p2 == p)
2619
            break;
2620
        len = p2 - p;
2621
        if (len > sizeof(line) - 1)
2622
            len = sizeof(line) - 1;
2623
        memcpy(line, p, len);
2624
        line[len] = '\0';
2625
        rtsp_parse_line(header, line);
2626
        p = p1 + 1;
2627
    }
2628

    
2629
    /* handle sequence number */
2630
    c->seq = header->seq;
2631

    
2632
    if (!strcmp(cmd, "DESCRIBE")) {
2633
        rtsp_cmd_describe(c, url);
2634
    } else if (!strcmp(cmd, "OPTIONS")) {
2635
        rtsp_cmd_options(c, url);
2636
    } else if (!strcmp(cmd, "SETUP")) {
2637
        rtsp_cmd_setup(c, url, header);
2638
    } else if (!strcmp(cmd, "PLAY")) {
2639
        rtsp_cmd_play(c, url, header);
2640
    } else if (!strcmp(cmd, "PAUSE")) {
2641
        rtsp_cmd_pause(c, url, header);
2642
    } else if (!strcmp(cmd, "TEARDOWN")) {
2643
        rtsp_cmd_teardown(c, url, header);
2644
    } else {
2645
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2646
    }
2647
 the_end:
2648
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2649
    c->pb = NULL; /* safety */
2650
    if (len < 0) {
2651
        /* XXX: cannot do more */
2652
        return -1;
2653
    }
2654
    c->buffer_ptr = c->pb_buffer;
2655
    c->buffer_end = c->pb_buffer + len;
2656
    c->state = RTSPSTATE_SEND_REPLY;
2657
    return 0;
2658
}
2659

    
2660
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2661
   AVFormatContext */
2662
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2663
                                   struct in_addr my_ip)
2664
{
2665
    ByteIOContext pb1, *pb = &pb1;
2666
    int i, payload_type, port, private_payload_type, j;
2667
    const char *ipstr, *title, *mediatype;
2668
    AVStream *st;
2669

    
2670
    if (url_open_dyn_buf(pb) < 0)
2671
        return -1;
2672

    
2673
    /* general media info */
2674

    
2675
    url_fprintf(pb, "v=0\n");
2676
    ipstr = inet_ntoa(my_ip);
2677
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2678
    title = stream->title;
2679
    if (title[0] == '\0')
2680
        title = "No Title";
2681
    url_fprintf(pb, "s=%s\n", title);
2682
    if (stream->comment[0] != '\0')
2683
        url_fprintf(pb, "i=%s\n", stream->comment);
2684
    if (stream->is_multicast) {
2685
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2686
    }
2687
    /* for each stream, we output the necessary info */
2688
    private_payload_type = RTP_PT_PRIVATE;
2689
    for(i = 0; i < stream->nb_streams; i++) {
2690
        st = stream->streams[i];
2691
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2692
            mediatype = "video";
2693
        } else {
2694
            switch(st->codec->codec_type) {
2695
            case CODEC_TYPE_AUDIO:
2696
                mediatype = "audio";
2697
                break;
2698
            case CODEC_TYPE_VIDEO:
2699
                mediatype = "video";
2700
                break;
2701
            default:
2702
                mediatype = "application";
2703
                break;
2704
            }
2705
        }
2706
        /* NOTE: the port indication is not correct in case of
2707
           unicast. It is not an issue because RTSP gives it */
2708
        payload_type = rtp_get_payload_type(st->codec);
2709
        if (payload_type < 0)
2710
            payload_type = private_payload_type++;
2711
        if (stream->is_multicast) {
2712
            port = stream->multicast_port + 2 * i;
2713
        } else {
2714
            port = 0;
2715
        }
2716
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2717
                    mediatype, port, payload_type);
2718
        if (payload_type >= RTP_PT_PRIVATE) {
2719
            /* for private payload type, we need to give more info */
2720
            switch(st->codec->codec_id) {
2721
            case CODEC_ID_MPEG4:
2722
                {
2723
                    uint8_t *data;
2724
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2725
                                payload_type, 90000);
2726
                    /* we must also add the mpeg4 header */
2727
                    data = st->codec->extradata;
2728
                    if (data) {
2729
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2730
                        for(j=0;j<st->codec->extradata_size;j++) {
2731
                            url_fprintf(pb, "%02x", data[j]);
2732
                        }
2733
                        url_fprintf(pb, "\n");
2734
                    }
2735
                }
2736
                break;
2737
            default:
2738
                /* XXX: add other codecs ? */
2739
                goto fail;
2740
            }
2741
        }
2742
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2743
    }
2744
    return url_close_dyn_buf(pb, pbuffer);
2745
 fail:
2746
    url_close_dyn_buf(pb, pbuffer);
2747
    av_free(*pbuffer);
2748
    return -1;
2749
}
2750

    
2751
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2752
{
2753
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2754
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2755
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2756
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2757
    url_fprintf(c->pb, "\r\n");
2758
}
2759

    
2760
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2761
{
2762
    FFStream *stream;
2763
    char path1[1024];
2764
    const char *path;
2765
    uint8_t *content;
2766
    int content_length, len;
2767
    struct sockaddr_in my_addr;
2768

    
2769
    /* find which url is asked */
2770
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2771
    path = path1;
2772
    if (*path == '/')
2773
        path++;
2774

    
2775
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2776
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2777
            !strcmp(path, stream->filename)) {
2778
            goto found;
2779
        }
2780
    }
2781
    /* no stream found */
2782
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2783
    return;
2784

    
2785
 found:
2786
    /* prepare the media description in sdp format */
2787

    
2788
    /* get the host IP */
2789
    len = sizeof(my_addr);
2790
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2791
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2792
    if (content_length < 0) {
2793
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2794
        return;
2795
    }
2796
    rtsp_reply_header(c, RTSP_STATUS_OK);
2797
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2798
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2799
    url_fprintf(c->pb, "\r\n");
2800
    put_buffer(c->pb, content, content_length);
2801
}
2802

    
2803
static HTTPContext *find_rtp_session(const char *session_id)
2804
{
2805
    HTTPContext *c;
2806

    
2807
    if (session_id[0] == '\0')
2808
        return NULL;
2809

    
2810
    for(c = first_http_ctx; c != NULL; c = c->next) {
2811
        if (!strcmp(c->session_id, session_id))
2812
            return c;
2813
    }
2814
    return NULL;
2815
}
2816

    
2817
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2818
{
2819
    RTSPTransportField *th;
2820
    int i;
2821

    
2822
    for(i=0;i<h->nb_transports;i++) {
2823
        th = &h->transports[i];
2824
        if (th->protocol == protocol)
2825
            return th;
2826
    }
2827
    return NULL;
2828
}
2829

    
2830
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2831
                           RTSPHeader *h)
2832
{
2833
    FFStream *stream;
2834
    int stream_index, port;
2835
    char buf[1024];
2836
    char path1[1024];
2837
    const char *path;
2838
    HTTPContext *rtp_c;
2839
    RTSPTransportField *th;
2840
    struct sockaddr_in dest_addr;
2841
    RTSPActionServerSetup setup;
2842

    
2843
    /* find which url is asked */
2844
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2845
    path = path1;
2846
    if (*path == '/')
2847
        path++;
2848

    
2849
    /* now check each stream */
2850
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2851
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2852
            /* accept aggregate filenames only if single stream */
2853
            if (!strcmp(path, stream->filename)) {
2854
                if (stream->nb_streams != 1) {
2855
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2856
                    return;
2857
                }
2858
                stream_index = 0;
2859
                goto found;
2860
            }
2861

    
2862
            for(stream_index = 0; stream_index < stream->nb_streams;
2863
                stream_index++) {
2864
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2865
                         stream->filename, stream_index);
2866
                if (!strcmp(path, buf))
2867
                    goto found;
2868
            }
2869
        }
2870
    }
2871
    /* no stream found */
2872
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2873
    return;
2874
 found:
2875

    
2876
    /* generate session id if needed */
2877
    if (h->session_id[0] == '\0') {
2878
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2879
                 av_random(&random_state), av_random(&random_state));
2880
    }
2881

    
2882
    /* find rtp session, and create it if none found */
2883
    rtp_c = find_rtp_session(h->session_id);
2884
    if (!rtp_c) {
2885
        /* always prefer UDP */
2886
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2887
        if (!th) {
2888
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2889
            if (!th) {
2890
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2891
                return;
2892
            }
2893
        }
2894

    
2895
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2896
                                   th->protocol);
2897
        if (!rtp_c) {
2898
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2899
            return;
2900
        }
2901

    
2902
        /* open input stream */
2903
        if (open_input_stream(rtp_c, "") < 0) {
2904
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2905
            return;
2906
        }
2907
    }
2908

    
2909
    /* test if stream is OK (test needed because several SETUP needs
2910
       to be done for a given file) */
2911
    if (rtp_c->stream != stream) {
2912
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2913
        return;
2914
    }
2915

    
2916
    /* test if stream is already set up */
2917
    if (rtp_c->rtp_ctx[stream_index]) {
2918
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2919
        return;
2920
    }
2921

    
2922
    /* check transport */
2923
    th = find_transport(h, rtp_c->rtp_protocol);
2924
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2925
                th->client_port_min <= 0)) {
2926
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2927
        return;
2928
    }
2929

    
2930
    /* setup default options */
2931
    setup.transport_option[0] = '\0';
2932
    dest_addr = rtp_c->from_addr;
2933
    dest_addr.sin_port = htons(th->client_port_min);
2934

    
2935
    /* add transport option if needed */
2936
    if (ff_rtsp_callback) {
2937
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2938
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2939
                             (char *)&setup, sizeof(setup),
2940
                             stream->rtsp_option) < 0) {
2941
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2942
            return;
2943
        }
2944
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2945
    }
2946

    
2947
    /* setup stream */
2948
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2949
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2950
        return;
2951
    }
2952

    
2953
    /* now everything is OK, so we can send the connection parameters */
2954
    rtsp_reply_header(c, RTSP_STATUS_OK);
2955
    /* session ID */
2956
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2957

    
2958
    switch(rtp_c->rtp_protocol) {
2959
    case RTSP_PROTOCOL_RTP_UDP:
2960
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2961
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2962
                    "client_port=%d-%d;server_port=%d-%d",
2963
                    th->client_port_min, th->client_port_min + 1,
2964
                    port, port + 1);
2965
        break;
2966
    case RTSP_PROTOCOL_RTP_TCP:
2967
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2968
                    stream_index * 2, stream_index * 2 + 1);
2969
        break;
2970
    default:
2971
        break;
2972
    }
2973
    if (setup.transport_option[0] != '\0') {
2974
        url_fprintf(c->pb, ";%s", setup.transport_option);
2975
    }
2976
    url_fprintf(c->pb, "\r\n");
2977

    
2978

    
2979
    url_fprintf(c->pb, "\r\n");
2980
}
2981

    
2982

    
2983
/* find an rtp connection by using the session ID. Check consistency
2984
   with filename */
2985
static HTTPContext *find_rtp_session_with_url(const char *url,
2986
                                              const char *session_id)
2987
{
2988
    HTTPContext *rtp_c;
2989
    char path1[1024];
2990
    const char *path;
2991
    char buf[1024];
2992
    int s;
2993

    
2994
    rtp_c = find_rtp_session(session_id);
2995
    if (!rtp_c)
2996
        return NULL;
2997

    
2998
    /* find which url is asked */
2999
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3000
    path = path1;
3001
    if (*path == '/')
3002
        path++;
3003
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3004
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3005
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3006
        rtp_c->stream->filename, s);
3007
      if(!strncmp(path, buf, sizeof(buf))) {
3008
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3009
        return rtp_c;
3010
      }
3011
    }
3012
    return NULL;
3013
}
3014

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

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

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

    
3032
#if 0
3033
    /* XXX: seek in stream */
3034
    if (h->range_start != AV_NOPTS_VALUE) {
3035
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3036
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3037
    }
3038
#endif
3039

    
3040
    rtp_c->state = HTTPSTATE_SEND_DATA;
3041

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

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

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

    
3059
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3060
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3061
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3062
        return;
3063
    }
3064

    
3065
    rtp_c->state = HTTPSTATE_READY;
3066
    rtp_c->first_pts = AV_NOPTS_VALUE;
3067
    /* now everything is OK, so we can send the connection parameters */
3068
    rtsp_reply_header(c, RTSP_STATUS_OK);
3069
    /* session ID */
3070
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3071
    url_fprintf(c->pb, "\r\n");
3072
}
3073

    
3074
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3075
{
3076
    HTTPContext *rtp_c;
3077

    
3078
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3079
    if (!rtp_c) {
3080
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3081
        return;
3082
    }
3083

    
3084
    /* abort the session */
3085
    close_connection(rtp_c);
3086

    
3087
    if (ff_rtsp_callback) {
3088
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3089
                         NULL, 0,
3090
                         rtp_c->stream->rtsp_option);
3091
    }
3092

    
3093
    /* now everything is OK, so we can send the connection parameters */
3094
    rtsp_reply_header(c, RTSP_STATUS_OK);
3095
    /* session ID */
3096
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3097
    url_fprintf(c->pb, "\r\n");
3098
}
3099

    
3100

    
3101
/********************************************************************/
3102
/* RTP handling */
3103

    
3104
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3105
                                       FFStream *stream, const char *session_id,
3106
                                       enum RTSPProtocol rtp_protocol)
3107
{
3108
    HTTPContext *c = NULL;
3109
    const char *proto_str;
3110

    
3111
    /* XXX: should output a warning page when coming
3112
       close to the connection limit */
3113
    if (nb_connections >= nb_max_connections)
3114
        goto fail;
3115

    
3116
    /* add a new connection */
3117
    c = av_mallocz(sizeof(HTTPContext));
3118
    if (!c)
3119
        goto fail;
3120

    
3121
    c->fd = -1;
3122
    c->poll_entry = NULL;
3123
    c->from_addr = *from_addr;
3124
    c->buffer_size = IOBUFFER_INIT_SIZE;
3125
    c->buffer = av_malloc(c->buffer_size);
3126
    if (!c->buffer)
3127
        goto fail;
3128
    nb_connections++;
3129
    c->stream = stream;
3130
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3131
    c->state = HTTPSTATE_READY;
3132
    c->is_packetized = 1;
3133
    c->rtp_protocol = rtp_protocol;
3134

    
3135
    /* protocol is shown in statistics */
3136
    switch(c->rtp_protocol) {
3137
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3138
        proto_str = "MCAST";
3139
        break;
3140
    case RTSP_PROTOCOL_RTP_UDP:
3141
        proto_str = "UDP";
3142
        break;
3143
    case RTSP_PROTOCOL_RTP_TCP:
3144
        proto_str = "TCP";
3145
        break;
3146
    default:
3147
        proto_str = "???";
3148
        break;
3149
    }
3150
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3151
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3152

    
3153
    current_bandwidth += stream->bandwidth;
3154

    
3155
    c->next = first_http_ctx;
3156
    first_http_ctx = c;
3157
    return c;
3158

    
3159
 fail:
3160
    if (c) {
3161
        av_free(c->buffer);
3162
        av_free(c);
3163
    }
3164
    return NULL;
3165
}
3166

    
3167
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3168
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3169
   used. */
3170
static int rtp_new_av_stream(HTTPContext *c,
3171
                             int stream_index, struct sockaddr_in *dest_addr,
3172
                             HTTPContext *rtsp_c)
3173
{
3174
    AVFormatContext *ctx;
3175
    AVStream *st;
3176
    char *ipaddr;
3177
    URLContext *h;
3178
    uint8_t *dummy_buf;
3179
    char buf2[32];
3180
    int max_packet_size;
3181

    
3182
    /* now we can open the relevant output stream */
3183
    ctx = av_alloc_format_context();
3184
    if (!ctx)
3185
        return -1;
3186
    ctx->oformat = &rtp_muxer;
3187

    
3188
    st = av_mallocz(sizeof(AVStream));
3189
    if (!st)
3190
        goto fail;
3191
    st->codec= avcodec_alloc_context();
3192
    ctx->nb_streams = 1;
3193
    ctx->streams[0] = st;
3194

    
3195
    if (!c->stream->feed ||
3196
        c->stream->feed == c->stream) {
3197
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3198
    } else {
3199
        memcpy(st,
3200
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3201
               sizeof(AVStream));
3202
    }
3203

    
3204
    /* build destination RTP address */
3205
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3206

    
3207
    switch(c->rtp_protocol) {
3208
    case RTSP_PROTOCOL_RTP_UDP:
3209
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3210
        /* RTP/UDP case */
3211

    
3212
        /* XXX: also pass as parameter to function ? */
3213
        if (c->stream->is_multicast) {
3214
            int ttl;
3215
            ttl = c->stream->multicast_ttl;
3216
            if (!ttl)
3217
                ttl = 16;
3218
            snprintf(ctx->filename, sizeof(ctx->filename),
3219
                     "rtp://%s:%d?multicast=1&ttl=%d",
3220
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3221
        } else {
3222
            snprintf(ctx->filename, sizeof(ctx->filename),
3223
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3224
        }
3225

    
3226
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3227
            goto fail;
3228
        c->rtp_handles[stream_index] = h;
3229
        max_packet_size = url_get_max_packet_size(h);
3230
        break;
3231
    case RTSP_PROTOCOL_RTP_TCP:
3232
        /* RTP/TCP case */
3233
        c->rtsp_c = rtsp_c;
3234
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3235
        break;
3236
    default:
3237
        goto fail;
3238
    }
3239

    
3240
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3241
             ipaddr, ntohs(dest_addr->sin_port),
3242
             ctime1(buf2),
3243
             c->stream->filename, stream_index, c->protocol);
3244

    
3245
    /* normally, no packets should be output here, but the packet size may be checked */
3246
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3247
        /* XXX: close stream */
3248
        goto fail;
3249
    }
3250
    av_set_parameters(ctx, NULL);
3251
    if (av_write_header(ctx) < 0) {
3252
    fail:
3253
        if (h)
3254
            url_close(h);
3255
        av_free(ctx);
3256
        return -1;
3257
    }
3258
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3259
    av_free(dummy_buf);
3260

    
3261
    c->rtp_ctx[stream_index] = ctx;
3262
    return 0;
3263
}
3264

    
3265
/********************************************************************/
3266
/* ffserver initialization */
3267

    
3268
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3269
{
3270
    AVStream *fst;
3271

    
3272
    fst = av_mallocz(sizeof(AVStream));
3273
    if (!fst)
3274
        return NULL;
3275
    fst->codec= avcodec_alloc_context();
3276
    fst->priv_data = av_mallocz(sizeof(FeedData));
3277
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3278
    fst->codec->coded_frame = &dummy_frame;
3279
    fst->index = stream->nb_streams;
3280
    av_set_pts_info(fst, 33, 1, 90000);
3281
    stream->streams[stream->nb_streams++] = fst;
3282
    return fst;
3283
}
3284

    
3285
/* return the stream number in the feed */
3286
static int add_av_stream(FFStream *feed, AVStream *st)
3287
{
3288
    AVStream *fst;
3289
    AVCodecContext *av, *av1;
3290
    int i;
3291

    
3292
    av = st->codec;
3293
    for(i=0;i<feed->nb_streams;i++) {
3294
        st = feed->streams[i];
3295
        av1 = st->codec;
3296
        if (av1->codec_id == av->codec_id &&
3297
            av1->codec_type == av->codec_type &&
3298
            av1->bit_rate == av->bit_rate) {
3299

    
3300
            switch(av->codec_type) {
3301
            case CODEC_TYPE_AUDIO:
3302
                if (av1->channels == av->channels &&
3303
                    av1->sample_rate == av->sample_rate)
3304
                    goto found;
3305
                break;
3306
            case CODEC_TYPE_VIDEO:
3307
                if (av1->width == av->width &&
3308
                    av1->height == av->height &&
3309
                    av1->time_base.den == av->time_base.den &&
3310
                    av1->time_base.num == av->time_base.num &&
3311
                    av1->gop_size == av->gop_size)
3312
                    goto found;
3313
                break;
3314
            default:
3315
                av_abort();
3316
            }
3317
        }
3318
    }
3319

    
3320
    fst = add_av_stream1(feed, av);
3321
    if (!fst)
3322
        return -1;
3323
    return feed->nb_streams - 1;
3324
 found:
3325
    return i;
3326
}
3327

    
3328
static void remove_stream(FFStream *stream)
3329
{
3330
    FFStream **ps;
3331
    ps = &first_stream;
3332
    while (*ps != NULL) {
3333
        if (*ps == stream) {
3334
            *ps = (*ps)->next;
3335
        } else {
3336
            ps = &(*ps)->next;
3337
        }
3338
    }
3339
}
3340

    
3341
/* specific mpeg4 handling : we extract the raw parameters */
3342
static void extract_mpeg4_header(AVFormatContext *infile)
3343
{
3344
    int mpeg4_count, i, size;
3345
    AVPacket pkt;
3346
    AVStream *st;
3347
    const uint8_t *p;
3348

    
3349
    mpeg4_count = 0;
3350
    for(i=0;i<infile->nb_streams;i++) {
3351
        st = infile->streams[i];
3352
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3353
            st->codec->extradata_size == 0) {
3354
            mpeg4_count++;
3355
        }
3356
    }
3357
    if (!mpeg4_count)
3358
        return;
3359

    
3360
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3361
    while (mpeg4_count > 0) {
3362
        if (av_read_packet(infile, &pkt) < 0)
3363
            break;
3364
        st = infile->streams[pkt.stream_index];
3365
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3366
            st->codec->extradata_size == 0) {
3367
            av_freep(&st->codec->extradata);
3368
            /* fill extradata with the header */
3369
            /* XXX: we make hard suppositions here ! */
3370
            p = pkt.data;
3371
            while (p < pkt.data + pkt.size - 4) {
3372
                /* stop when vop header is found */
3373
                if (p[0] == 0x00 && p[1] == 0x00 &&
3374
                    p[2] == 0x01 && p[3] == 0xb6) {
3375
                    size = p - pkt.data;
3376
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3377
                    st->codec->extradata = av_malloc(size);
3378
                    st->codec->extradata_size = size;
3379
                    memcpy(st->codec->extradata, pkt.data, size);
3380
                    break;
3381
                }
3382
                p++;
3383
            }
3384
            mpeg4_count--;
3385
        }
3386
        av_free_packet(&pkt);
3387
    }
3388
}
3389

    
3390
/* compute the needed AVStream for each file */
3391
static void build_file_streams(void)
3392
{
3393
    FFStream *stream, *stream_next;
3394
    AVFormatContext *infile;
3395
    int i;
3396

    
3397
    /* gather all streams */
3398
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3399
        stream_next = stream->next;
3400
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3401
            !stream->feed) {
3402
            /* the stream comes from a file */
3403
            /* try to open the file */
3404
            /* open stream */
3405
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3406
            if (stream->fmt == &rtp_muxer) {
3407
                /* specific case : if transport stream output to RTP,
3408
                   we use a raw transport stream reader */
3409
                stream->ap_in->mpeg2ts_raw = 1;
3410
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3411
            }
3412

    
3413
            if (av_open_input_file(&infile, stream->feed_filename,
3414
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3415
                http_log("%s not found", stream->feed_filename);
3416
                /* remove stream (no need to spend more time on it) */
3417
            fail:
3418
                remove_stream(stream);
3419
            } else {
3420
                /* find all the AVStreams inside and reference them in
3421
                   'stream' */
3422
                if (av_find_stream_info(infile) < 0) {
3423
                    http_log("Could not find codec parameters from '%s'",
3424
                             stream->feed_filename);
3425
                    av_close_input_file(infile);
3426
                    goto fail;
3427
                }
3428
                extract_mpeg4_header(infile);
3429

    
3430
                for(i=0;i<infile->nb_streams;i++) {
3431
                    add_av_stream1(stream, infile->streams[i]->codec);
3432
                }
3433
                av_close_input_file(infile);
3434
            }
3435
        }
3436
    }
3437
}
3438

    
3439
/* compute the needed AVStream for each feed */
3440
static void build_feed_streams(void)
3441
{
3442
    FFStream *stream, *feed;
3443
    int i;
3444

    
3445
    /* gather all streams */
3446
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3447
        feed = stream->feed;
3448
        if (feed) {
3449
            if (!stream->is_feed) {
3450
                /* we handle a stream coming from a feed */
3451
                for(i=0;i<stream->nb_streams;i++) {
3452
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3453
                }
3454
            }
3455
        }
3456
    }
3457

    
3458
    /* gather all streams */
3459
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3460
        feed = stream->feed;
3461
        if (feed) {
3462
            if (stream->is_feed) {
3463
                for(i=0;i<stream->nb_streams;i++) {
3464
                    stream->feed_streams[i] = i;
3465
                }
3466
            }
3467
        }
3468
    }
3469

    
3470
    /* create feed files if needed */
3471
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3472
        int fd;
3473

    
3474
        if (url_exist(feed->feed_filename)) {
3475
            /* See if it matches */
3476
            AVFormatContext *s;
3477
            int matches = 0;
3478

    
3479
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3480
                /* Now see if it matches */
3481
                if (s->nb_streams == feed->nb_streams) {
3482
                    matches = 1;
3483
                    for(i=0;i<s->nb_streams;i++) {
3484
                        AVStream *sf, *ss;
3485
                        sf = feed->streams[i];
3486
                        ss = s->streams[i];
3487

    
3488
                        if (sf->index != ss->index ||
3489
                            sf->id != ss->id) {
3490
                            printf("Index & Id do not match for stream %d (%s)\n",
3491
                                   i, feed->feed_filename);
3492
                            matches = 0;
3493
                        } else {
3494
                            AVCodecContext *ccf, *ccs;
3495

    
3496
                            ccf = sf->codec;
3497
                            ccs = ss->codec;
3498
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3499

    
3500
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3501
                                printf("Codecs do not match for stream %d\n", i);
3502
                                matches = 0;
3503
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3504
                                printf("Codec bitrates do not match for stream %d\n", i);
3505
                                matches = 0;
3506
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3507
                                if (CHECK_CODEC(time_base.den) ||
3508
                                    CHECK_CODEC(time_base.num) ||
3509
                                    CHECK_CODEC(width) ||
3510
                                    CHECK_CODEC(height)) {
3511
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3512
                                    matches = 0;
3513
                                }
3514
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3515
                                if (CHECK_CODEC(sample_rate) ||
3516
                                    CHECK_CODEC(channels) ||
3517
                                    CHECK_CODEC(frame_size)) {
3518
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3519
                                    matches = 0;
3520
                                }
3521
                            } else {
3522
                                printf("Unknown codec type\n");
3523
                                matches = 0;
3524
                            }
3525
                        }
3526
                        if (!matches) {
3527
                            break;
3528
                        }
3529
                    }
3530
                } else {
3531
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3532
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3533
                }
3534

    
3535
                av_close_input_file(s);
3536
            } else {
3537
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3538
                        feed->feed_filename);
3539
            }
3540
            if (!matches) {
3541
                if (feed->readonly) {
3542
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3543
                        feed->feed_filename);
3544
                    exit(1);
3545
                }
3546
                unlink(feed->feed_filename);
3547
            }
3548
        }
3549
        if (!url_exist(feed->feed_filename)) {
3550
            AVFormatContext s1, *s = &s1;
3551

    
3552
            if (feed->readonly) {
3553
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3554
                    feed->feed_filename);
3555
                exit(1);
3556
            }
3557

    
3558
            /* only write the header of the ffm file */
3559
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3560
                fprintf(stderr, "Could not open output feed file '%s'\n",
3561
                        feed->feed_filename);
3562
                exit(1);
3563
            }
3564
            s->oformat = feed->fmt;
3565
            s->nb_streams = feed->nb_streams;
3566
            for(i=0;i<s->nb_streams;i++) {
3567
                AVStream *st;
3568
                st = feed->streams[i];
3569
                s->streams[i] = st;
3570
            }
3571
            av_set_parameters(s, NULL);
3572
            if (av_write_header(s) < 0) {
3573
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3574
                exit(1);
3575
            }
3576
            /* XXX: need better api */
3577
            av_freep(&s->priv_data);
3578
            url_fclose(&s->pb);
3579
        }
3580
        /* get feed size and write index */
3581
        fd = open(feed->feed_filename, O_RDONLY);
3582
        if (fd < 0) {
3583
            fprintf(stderr, "Could not open output feed file '%s'\n",
3584
                    feed->feed_filename);
3585
            exit(1);
3586
        }
3587

    
3588
        feed->feed_write_index = ffm_read_write_index(fd);
3589
        feed->feed_size = lseek(fd, 0, SEEK_END);
3590
        /* ensure that we do not wrap before the end of file */
3591
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3592
            feed->feed_max_size = feed->feed_size;
3593

    
3594
        close(fd);
3595
    }
3596
}
3597

    
3598
/* compute the bandwidth used by each stream */
3599
static void compute_bandwidth(void)
3600
{
3601
    int bandwidth, i;
3602
    FFStream *stream;
3603

    
3604
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3605
        bandwidth = 0;
3606
        for(i=0;i<stream->nb_streams;i++) {
3607
            AVStream *st = stream->streams[i];
3608
            switch(st->codec->codec_type) {
3609
            case CODEC_TYPE_AUDIO:
3610
            case CODEC_TYPE_VIDEO:
3611
                bandwidth += st->codec->bit_rate;
3612
                break;
3613
            default:
3614
                break;
3615
            }
3616
        }
3617
        stream->bandwidth = (bandwidth + 999) / 1000;
3618
    }
3619
}
3620

    
3621
static void get_arg(char *buf, int buf_size, const char **pp)
3622
{
3623
    const char *p;
3624
    char *q;
3625
    int quote;
3626

    
3627
    p = *pp;
3628
    while (isspace(*p)) p++;
3629
    q = buf;
3630
    quote = 0;
3631
    if (*p == '\"' || *p == '\'')
3632
        quote = *p++;
3633
    for(;;) {
3634
        if (quote) {
3635
            if (*p == quote)
3636
                break;
3637
        } else {
3638
            if (isspace(*p))
3639
                break;
3640
        }
3641
        if (*p == '\0')
3642
            break;
3643
        if ((q - buf) < buf_size - 1)
3644
            *q++ = *p;
3645
        p++;
3646
    }
3647
    *q = '\0';
3648
    if (quote && *p == quote)
3649
        p++;
3650
    *pp = p;
3651
}
3652

    
3653
/* add a codec and set the default parameters */
3654
static void add_codec(FFStream *stream, AVCodecContext *av)
3655
{
3656
    AVStream *st;
3657

    
3658
    /* compute default parameters */
3659
    switch(av->codec_type) {
3660
    case CODEC_TYPE_AUDIO:
3661
        if (av->bit_rate == 0)
3662
            av->bit_rate = 64000;
3663
        if (av->sample_rate == 0)
3664
            av->sample_rate = 22050;
3665
        if (av->channels == 0)
3666
            av->channels = 1;
3667
        break;
3668
    case CODEC_TYPE_VIDEO:
3669
        if (av->bit_rate == 0)
3670
            av->bit_rate = 64000;
3671
        if (av->time_base.num == 0){
3672
            av->time_base.den = 5;
3673
            av->time_base.num = 1;
3674
        }
3675
        if (av->width == 0 || av->height == 0) {
3676
            av->width = 160;
3677
            av->height = 128;
3678
        }
3679
        /* Bitrate tolerance is less for streaming */
3680
        if (av->bit_rate_tolerance == 0)
3681
            av->bit_rate_tolerance = av->bit_rate / 4;
3682
        if (av->qmin == 0)
3683
            av->qmin = 3;
3684
        if (av->qmax == 0)
3685
            av->qmax = 31;
3686
        if (av->max_qdiff == 0)
3687
            av->max_qdiff = 3;
3688
        av->qcompress = 0.5;
3689
        av->qblur = 0.5;
3690

    
3691
        if (!av->nsse_weight)
3692
            av->nsse_weight = 8;
3693

    
3694
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3695
        av->me_method = ME_EPZS;
3696
        av->rc_buffer_aggressivity = 1.0;
3697

    
3698
        if (!av->rc_eq)
3699
            av->rc_eq = "tex^qComp";
3700
        if (!av->i_quant_factor)
3701
            av->i_quant_factor = -0.8;
3702
        if (!av->b_quant_factor)
3703
            av->b_quant_factor = 1.25;
3704
        if (!av->b_quant_offset)
3705
            av->b_quant_offset = 1.25;
3706
        if (!av->rc_max_rate)
3707
            av->rc_max_rate = av->bit_rate * 2;
3708

    
3709
        if (av->rc_max_rate && !av->rc_buffer_size) {
3710
            av->rc_buffer_size = av->rc_max_rate;
3711
        }
3712

    
3713

    
3714
        break;
3715
    default:
3716
        av_abort();
3717
    }
3718

    
3719
    st = av_mallocz(sizeof(AVStream));
3720
    if (!st)
3721
        return;
3722
    st->codec = avcodec_alloc_context();
3723
    stream->streams[stream->nb_streams++] = st;
3724
    memcpy(st->codec, av, sizeof(AVCodecContext));
3725
}
3726

    
3727
static int opt_audio_codec(const char *arg)
3728
{
3729
    AVCodec *p;
3730

    
3731
    p = first_avcodec;
3732
    while (p) {
3733
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3734
            break;
3735
        p = p->next;
3736
    }
3737
    if (p == NULL) {
3738
        return CODEC_ID_NONE;
3739
    }
3740

    
3741
    return p->id;
3742
}
3743

    
3744
static int opt_video_codec(const char *arg)
3745
{
3746
    AVCodec *p;
3747

    
3748
    p = first_avcodec;
3749
    while (p) {
3750
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3751
            break;
3752
        p = p->next;
3753
    }
3754
    if (p == NULL) {
3755
        return CODEC_ID_NONE;
3756
    }
3757

    
3758
    return p->id;
3759
}
3760

    
3761
/* simplistic plugin support */
3762

    
3763
#ifdef HAVE_DLOPEN
3764
static void load_module(const char *filename)
3765
{
3766
    void *dll;
3767
    void (*init_func)(void);
3768
    dll = dlopen(filename, RTLD_NOW);
3769
    if (!dll) {
3770
        fprintf(stderr, "Could not load module '%s' - %s\n",
3771
                filename, dlerror());
3772
        return;
3773
    }
3774

    
3775
    init_func = dlsym(dll, "ffserver_module_init");
3776
    if (!init_func) {
3777
        fprintf(stderr,
3778
                "%s: init function 'ffserver_module_init()' not found\n",
3779
                filename);
3780
        dlclose(dll);
3781
    }
3782

    
3783
    init_func();
3784
}
3785
#endif
3786

    
3787
static int parse_ffconfig(const char *filename)
3788
{
3789
    FILE *f;
3790
    char line[1024];
3791
    char cmd[64];
3792
    char arg[1024];
3793
    const char *p;
3794
    int val, errors, line_num;
3795
    FFStream **last_stream, *stream, *redirect;
3796
    FFStream **last_feed, *feed;
3797
    AVCodecContext audio_enc, video_enc;
3798
    int audio_id, video_id;
3799

    
3800
    f = fopen(filename, "r");
3801
    if (!f) {
3802
        perror(filename);
3803
        return -1;
3804
    }
3805

    
3806
    errors = 0;
3807
    line_num = 0;
3808
    first_stream = NULL;
3809
    last_stream = &first_stream;
3810
    first_feed = NULL;
3811
    last_feed = &first_feed;
3812
    stream = NULL;
3813
    feed = NULL;
3814
    redirect = NULL;
3815
    audio_id = CODEC_ID_NONE;
3816
    video_id = CODEC_ID_NONE;
3817
    for(;;) {
3818
        if (fgets(line, sizeof(line), f) == NULL)
3819
            break;
3820
        line_num++;
3821
        p = line;
3822
        while (isspace(*p))
3823
            p++;
3824
        if (*p == '\0' || *p == '#')
3825
            continue;
3826

    
3827
        get_arg(cmd, sizeof(cmd), &p);
3828

    
3829
        if (!strcasecmp(cmd, "Port")) {
3830
            get_arg(arg, sizeof(arg), &p);
3831
            my_http_addr.sin_port = htons (atoi(arg));
3832
        } else if (!strcasecmp(cmd, "BindAddress")) {
3833
            get_arg(arg, sizeof(arg), &p);
3834
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3835
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3836
                        filename, line_num, arg);
3837
                errors++;
3838
            }
3839
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3840
            ffserver_daemon = 0;
3841
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3842
            get_arg(arg, sizeof(arg), &p);
3843
            my_rtsp_addr.sin_port = htons (atoi(arg));
3844
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3845
            get_arg(arg, sizeof(arg), &p);
3846
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3847
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3848
                        filename, line_num, arg);
3849
                errors++;
3850
            }
3851
        } else if (!strcasecmp(cmd, "MaxClients")) {
3852
            get_arg(arg, sizeof(arg), &p);
3853
            val = atoi(arg);
3854
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3855
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3856
                        filename, line_num, arg);
3857
                errors++;
3858
            } else {
3859
                nb_max_connections = val;
3860
            }
3861
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3862
            get_arg(arg, sizeof(arg), &p);
3863
            val = atoi(arg);
3864
            if (val < 10 || val > 100000) {
3865
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3866
                        filename, line_num, arg);
3867
                errors++;
3868
            } else {
3869
                max_bandwidth = val;
3870
            }
3871
        } else if (!strcasecmp(cmd, "CustomLog")) {
3872
            get_arg(logfilename, sizeof(logfilename), &p);
3873
        } else if (!strcasecmp(cmd, "<Feed")) {
3874
            /*********************************************/
3875
            /* Feed related options */
3876
            char *q;
3877
            if (stream || feed) {
3878
                fprintf(stderr, "%s:%d: Already in a tag\n",
3879
                        filename, line_num);
3880
            } else {
3881
                feed = av_mallocz(sizeof(FFStream));
3882
                /* add in stream list */
3883
                *last_stream = feed;
3884
                last_stream = &feed->next;
3885
                /* add in feed list */
3886
                *last_feed = feed;
3887
                last_feed = &feed->next_feed;
3888

    
3889
                get_arg(feed->filename, sizeof(feed->filename), &p);
3890
                q = strrchr(feed->filename, '>');
3891
                if (*q)
3892
                    *q = '\0';
3893
                feed->fmt = guess_format("ffm", NULL, NULL);
3894
                /* defaut feed file */
3895
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3896
                         "/tmp/%s.ffm", feed->filename);
3897
                feed->feed_max_size = 5 * 1024 * 1024;
3898
                feed->is_feed = 1;
3899
                feed->feed = feed; /* self feeding :-) */
3900
            }
3901
        } else if (!strcasecmp(cmd, "Launch")) {
3902
            if (feed) {
3903
                int i;
3904

    
3905
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3906

    
3907
                for (i = 0; i < 62; i++) {
3908
                    char argbuf[256];
3909

    
3910
                    get_arg(argbuf, sizeof(argbuf), &p);
3911
                    if (!argbuf[0])
3912
                        break;
3913

    
3914
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3915
                    strcpy(feed->child_argv[i], argbuf);
3916
                }
3917

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

    
3920
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3921
                    "http://%s:%d/%s",
3922
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3923
                    inet_ntoa(my_http_addr.sin_addr),
3924
                    ntohs(my_http_addr.sin_port), feed->filename);
3925

    
3926
                if (ffserver_debug)
3927
                {
3928
                    int j;
3929
                    fprintf(stdout, "Launch commandline: ");
3930
                    for (j = 0; j <= i; j++)
3931
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3932
                    fprintf(stdout, "\n");
3933
                }
3934
            }
3935
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3936
            if (feed) {
3937
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3938
                feed->readonly = 1;
3939
            } else if (stream) {
3940
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3941
            }
3942
        } else if (!strcasecmp(cmd, "File")) {
3943
            if (feed) {
3944
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3945
            } else if (stream) {
3946
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3947
            }
3948
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3949
            if (feed) {
3950
                const char *p1;
3951
                double fsize;
3952

    
3953
                get_arg(arg, sizeof(arg), &p);
3954
                p1 = arg;
3955
                fsize = strtod(p1, (char **)&p1);
3956
                switch(toupper(*p1)) {
3957
                case 'K':
3958
                    fsize *= 1024;
3959
                    break;
3960
                case 'M':
3961
                    fsize *= 1024 * 1024;
3962
                    break;
3963
                case 'G':
3964
                    fsize *= 1024 * 1024 * 1024;
3965
                    break;
3966
                }
3967
                feed->feed_max_size = (int64_t)fsize;
3968
            }
3969
        } else if (!strcasecmp(cmd, "</Feed>")) {
3970
            if (!feed) {
3971
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3972
                        filename, line_num);
3973
                errors++;
3974
#if 0
3975
            } else {
3976
                /* Make sure that we start out clean */
3977
                if (unlink(feed->feed_filename) < 0
3978
                    && errno != ENOENT) {
3979
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3980
                        filename, line_num, feed->feed_filename, strerror(errno));
3981
                    errors++;
3982
                }
3983
#endif
3984
            }
3985
            feed = NULL;
3986
        } else if (!strcasecmp(cmd, "<Stream")) {
3987
            /*********************************************/
3988
            /* Stream related options */
3989
            char *q;
3990
            if (stream || feed) {
3991
                fprintf(stderr, "%s:%d: Already in a tag\n",
3992
                        filename, line_num);
3993
            } else {
3994
                stream = av_mallocz(sizeof(FFStream));
3995
                *last_stream = stream;
3996
                last_stream = &stream->next;
3997

    
3998
                get_arg(stream->filename, sizeof(stream->filename), &p);
3999
                q = strrchr(stream->filename, '>');
4000
                if (*q)
4001
                    *q = '\0';
4002
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
4003
                memset(&audio_enc, 0, sizeof(AVCodecContext));
4004
                memset(&video_enc, 0, sizeof(AVCodecContext));
4005
                audio_id = CODEC_ID_NONE;
4006
                video_id = CODEC_ID_NONE;
4007
                if (stream->fmt) {
4008
                    audio_id = stream->fmt->audio_codec;
4009
                    video_id = stream->fmt->video_codec;
4010
                }
4011
            }
4012
        } else if (!strcasecmp(cmd, "Feed")) {
4013
            get_arg(arg, sizeof(arg), &p);
4014
            if (stream) {
4015
                FFStream *sfeed;
4016

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

    
4135
                get_arg(arg, sizeof(arg), &p);
4136

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

    
4287
            get_arg(arg, sizeof(arg), &p);
4288
            if (strcasecmp(arg, "allow") == 0) {
4289
                acl.action = IP_ALLOW;
4290
            } else if (strcasecmp(arg, "deny") == 0) {
4291
                acl.action = IP_DENY;
4292
            } else {
4293
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4294
                        filename, line_num, arg);
4295
                errors++;
4296
            }
4297

    
4298
            get_arg(arg, sizeof(arg), &p);
4299

    
4300
            he = gethostbyname(arg);
4301
            if (!he) {
4302
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4303
                        filename, line_num, arg);
4304
                errors++;
4305
            } else {
4306
                /* Only take the first */
4307
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4308
                acl.last = acl.first;
4309
            }
4310

    
4311
            get_arg(arg, sizeof(arg), &p);
4312

    
4313
            if (arg[0]) {
4314
                he = gethostbyname(arg);
4315
                if (!he) {
4316
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4317
                            filename, line_num, arg);
4318
                    errors++;
4319
                } else {
4320
                    /* Only take the first */
4321
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4322
                }
4323
            }
4324

    
4325
            if (!errors) {
4326
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4327
                IPAddressACL **naclp = 0;
4328

    
4329
                acl.next = 0;
4330
                *nacl = acl;
4331

    
4332
                if (stream) {
4333
                    naclp = &stream->acl;
4334
                } else if (feed) {
4335
                    naclp = &feed->acl;
4336
                } else {
4337
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4338
                            filename, line_num);
4339
                    errors++;
4340
                }
4341

    
4342
                if (naclp) {
4343
                    while (*naclp)
4344
                        naclp = &(*naclp)->next;
4345

    
4346
                    *naclp = nacl;
4347
                }
4348
            }
4349
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4350
            get_arg(arg, sizeof(arg), &p);
4351
            if (stream) {
4352
                av_freep(&stream->rtsp_option);
4353
                stream->rtsp_option = av_strdup(arg);
4354
            }
4355
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4356
            get_arg(arg, sizeof(arg), &p);
4357
            if (stream) {
4358
                if (!inet_aton(arg, &stream->multicast_ip)) {
4359
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
4360
                            filename, line_num, arg);
4361
                    errors++;
4362
                }
4363
                stream->is_multicast = 1;
4364
                stream->loop = 1; /* default is looping */
4365
            }
4366
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4367
            get_arg(arg, sizeof(arg), &p);
4368
            if (stream) {
4369
                stream->multicast_port = atoi(arg);
4370
            }
4371
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4372
            get_arg(arg, sizeof(arg), &p);
4373
            if (stream) {
4374
                stream->multicast_ttl = atoi(arg);
4375
            }
4376
        } else if (!strcasecmp(cmd, "NoLoop")) {
4377
            if (stream) {
4378
                stream->loop = 0;
4379
            }
4380
        } else if (!strcasecmp(cmd, "</Stream>")) {
4381
            if (!stream) {
4382
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4383
                        filename, line_num);
4384
                errors++;
4385
            }
4386
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4387
                if (audio_id != CODEC_ID_NONE) {
4388
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4389
                    audio_enc.codec_id = audio_id;
4390
                    add_codec(stream, &audio_enc);
4391
                }
4392
                if (video_id != CODEC_ID_NONE) {
4393
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4394
                    video_enc.codec_id = video_id;
4395
                    add_codec(stream, &video_enc);
4396
                }
4397
            }
4398
            stream = NULL;
4399
        } else if (!strcasecmp(cmd, "<Redirect")) {
4400
            /*********************************************/
4401
            char *q;
4402
            if (stream || feed || redirect) {
4403
                fprintf(stderr, "%s:%d: Already in a tag\n",
4404
                        filename, line_num);
4405
                errors++;
4406
            } else {
4407
                redirect = av_mallocz(sizeof(FFStream));
4408
                *last_stream = redirect;
4409
                last_stream = &redirect->next;
4410

    
4411
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4412
                q = strrchr(redirect->filename, '>');
4413
                if (*q)
4414
                    *q = '\0';
4415
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4416
            }
4417
        } else if (!strcasecmp(cmd, "URL")) {
4418
            if (redirect) {
4419
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4420
            }
4421
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4422
            if (!redirect) {
4423
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4424
                        filename, line_num);
4425
                errors++;
4426
            }
4427
            if (!redirect->feed_filename[0]) {
4428
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4429
                        filename, line_num);
4430
                errors++;
4431
            }
4432
            redirect = NULL;
4433
        } else if (!strcasecmp(cmd, "LoadModule")) {
4434
            get_arg(arg, sizeof(arg), &p);
4435
#ifdef HAVE_DLOPEN
4436
            load_module(arg);
4437
#else
4438
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4439
                    filename, line_num, arg);
4440
            errors++;
4441
#endif
4442
        } else {
4443
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4444
                    filename, line_num, cmd);
4445
            errors++;
4446
        }
4447
    }
4448

    
4449
    fclose(f);
4450
    if (errors)
4451
        return -1;
4452
    else
4453
        return 0;
4454
}
4455

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

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

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

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

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

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

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

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

    
4516
    need_to_start_children = 1;
4517
}
4518

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

    
4525
    av_register_all();
4526

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

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

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

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

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

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

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

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

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

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

    
4589
    build_file_streams();
4590

    
4591
    build_feed_streams();
4592

    
4593
    compute_bandwidth();
4594

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

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

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

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

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

    
4637
    return 0;
4638
}