Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 0bdacf29

History | View | Annotate | Download (151 KB)

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

    
24
#include <stdarg.h>
25
#include <unistd.h>
26
#include <fcntl.h>
27
#include <sys/ioctl.h>
28
#ifdef HAVE_SYS_POLL_H
29
#include <sys/poll.h>
30
#endif
31
#include <errno.h>
32
#include <sys/time.h>
33
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
34
#include <time.h>
35
#include <sys/wait.h>
36
#include <signal.h>
37
#ifdef HAVE_DLFCN_H
38
#include <dlfcn.h>
39
#endif
40

    
41
#include "network.h"
42
#include "version.h"
43
#include "ffserver.h"
44
#include "random.h"
45

    
46
#undef exit
47

    
48
/* maximum number of simultaneous HTTP connections */
49
#define HTTP_MAX_CONNECTIONS 2000
50

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

    
61
    RTSPSTATE_WAIT_REQUEST,
62
    RTSPSTATE_SEND_REPLY,
63
    RTSPSTATE_SEND_PACKET,
64
};
65

    
66
const char *http_state[] = {
67
    "HTTP_WAIT_REQUEST",
68
    "HTTP_SEND_HEADER",
69

    
70
    "SEND_DATA_HEADER",
71
    "SEND_DATA",
72
    "SEND_DATA_TRAILER",
73
    "RECEIVE_DATA",
74
    "WAIT_FEED",
75
    "READY",
76

    
77
    "RTSP_WAIT_REQUEST",
78
    "RTSP_SEND_REPLY",
79
    "RTSP_SEND_PACKET",
80
};
81

    
82
#define IOBUFFER_INIT_SIZE 8192
83

    
84
/* timeouts are in ms */
85
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
86
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
87

    
88
#define SYNC_TIMEOUT (10 * 1000)
89

    
90
typedef struct {
91
    int64_t count1, count2;
92
    int64_t time1, time2;
93
} DataRateData;
94

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

    
140
    /* RTSP state specific */
141
    uint8_t *pb_buffer; /* XXX: use that in all the code */
142
    ByteIOContext *pb;
143
    int seq; /* RTSP sequence number */
144

    
145
    /* RTP state specific */
146
    enum RTSPProtocol rtp_protocol;
147
    char session_id[32]; /* session id */
148
    AVFormatContext *rtp_ctx[MAX_STREAMS];
149

    
150
    /* RTP/UDP specific */
151
    URLContext *rtp_handles[MAX_STREAMS];
152

    
153
    /* RTP/TCP specific */
154
    struct HTTPContext *rtsp_c;
155
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
156
} HTTPContext;
157

    
158
static AVFrame dummy_frame;
159

    
160
/* each generated stream is described here */
161
enum StreamType {
162
    STREAM_TYPE_LIVE,
163
    STREAM_TYPE_STATUS,
164
    STREAM_TYPE_REDIRECT,
165
};
166

    
167
enum IPAddressAction {
168
    IP_ALLOW = 1,
169
    IP_DENY,
170
};
171

    
172
typedef struct IPAddressACL {
173
    struct IPAddressACL *next;
174
    enum IPAddressAction action;
175
    /* These are in host order */
176
    struct in_addr first;
177
    struct in_addr last;
178
} IPAddressACL;
179

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

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

    
228
typedef struct FeedData {
229
    long long data_count;
230
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
231
} FeedData;
232

    
233
static struct sockaddr_in my_http_addr;
234
static struct sockaddr_in my_rtsp_addr;
235

    
236
static char logfilename[1024];
237
static HTTPContext *first_http_ctx;
238
static FFStream *first_feed;   /* contains only feeds */
239
static FFStream *first_stream; /* contains all streams, including feeds */
240

    
241
static void new_connection(int server_fd, int is_rtsp);
242
static void close_connection(HTTPContext *c);
243

    
244
/* HTTP handling */
245
static int handle_connection(HTTPContext *c);
246
static int http_parse_request(HTTPContext *c);
247
static int http_send_data(HTTPContext *c);
248
static void compute_stats(HTTPContext *c);
249
static int open_input_stream(HTTPContext *c, const char *info);
250
static int http_start_receive_data(HTTPContext *c);
251
static int http_receive_data(HTTPContext *c);
252

    
253
/* RTSP handling */
254
static int rtsp_parse_request(HTTPContext *c);
255
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
256
static void rtsp_cmd_options(HTTPContext *c, const char *url);
257
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
258
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
259
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
260
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
261

    
262
/* SDP handling */
263
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
264
                                   struct in_addr my_ip);
265

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

    
274
static const char *my_program_name;
275
static const char *my_program_dir;
276

    
277
static int ffserver_debug;
278
static int ffserver_daemon;
279
static int no_launch;
280
static int need_to_start_children;
281

    
282
static int nb_max_connections;
283
static int nb_connections;
284

    
285
static int max_bandwidth;
286
static int current_bandwidth;
287

    
288
static int64_t cur_time;           // Making this global saves on passing it around everywhere
289

    
290
static AVRandomState random_state;
291

    
292
static FILE *logfile = NULL;
293

    
294
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
295
{
296
    va_list ap;
297
    va_start(ap, fmt);
298

    
299
    if (logfile) {
300
        vfprintf(logfile, fmt, ap);
301
        fflush(logfile);
302
    }
303
    va_end(ap);
304
}
305

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

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

    
320
static void log_connection(HTTPContext *c)
321
{
322
    char buf2[32];
323

    
324
    if (c->suppress_log)
325
        return;
326

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

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

    
348
/* In bytes per second */
349
static int compute_datarate(DataRateData *drd, int64_t count)
350
{
351
    if (cur_time == drd->time1)
352
        return 0;
353

    
354
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
355
}
356

    
357

    
358
static void start_children(FFStream *feed)
359
{
360
    if (no_launch)
361
        return;
362

    
363
    for (; feed; feed = feed->next) {
364
        if (feed->child_argv && !feed->pid) {
365
            feed->pid_start = time(0);
366

    
367
            feed->pid = fork();
368

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

    
379
                for (i = 3; i < 256; i++) {
380
                    close(i);
381
                }
382

    
383
                if (!ffserver_debug) {
384
                    i = open("/dev/null", O_RDWR);
385
                    if (i)
386
                        dup2(i, 0);
387
                    dup2(i, 1);
388
                    dup2(i, 2);
389
                    if (i)
390
                        close(i);
391
                }
392

    
393
                pstrcpy(pathname, sizeof(pathname), my_program_name);
394

    
395
                slash = strrchr(pathname, '/');
396
                if (!slash) {
397
                    slash = pathname;
398
                } else {
399
                    slash++;
400
                }
401
                strcpy(slash, "ffmpeg");
402

    
403
                /* This is needed to make relative pathnames work */
404
                chdir(my_program_dir);
405

    
406
                signal(SIGPIPE, SIG_DFL);
407

    
408
                execvp(pathname, feed->child_argv);
409

    
410
                _exit(1);
411
            }
412
        }
413
    }
414
}
415

    
416
/* open a listening socket */
417
static int socket_open_listen(struct sockaddr_in *my_addr)
418
{
419
    int server_fd, tmp;
420

    
421
    server_fd = socket(AF_INET,SOCK_STREAM,0);
422
    if (server_fd < 0) {
423
        perror ("socket");
424
        return -1;
425
    }
426

    
427
    tmp = 1;
428
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
429

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

    
438
    if (listen (server_fd, 5) < 0) {
439
        perror ("listen");
440
        closesocket(server_fd);
441
        return -1;
442
    }
443
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
444

    
445
    return server_fd;
446
}
447

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

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

    
464
            /* choose a port if none given */
465
            if (stream->multicast_port == 0) {
466
                stream->multicast_port = default_port;
467
                default_port += 100;
468
            }
469

    
470
            dest_addr.sin_family = AF_INET;
471
            dest_addr.sin_addr = stream->multicast_ip;
472
            dest_addr.sin_port = htons(stream->multicast_port);
473

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

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

    
497
            /* change state to send data */
498
            rtp_c->state = HTTPSTATE_SEND_DATA;
499
        }
500
    }
501
}
502

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

    
510
    server_fd = socket_open_listen(&my_http_addr);
511
    if (server_fd < 0)
512
        return -1;
513

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

    
518
    http_log("ffserver started.\n");
519

    
520
    start_children(first_feed);
521

    
522
    first_http_ctx = NULL;
523
    nb_connections = 0;
524

    
525
    start_multicast();
526

    
527
    for(;;) {
528
        poll_entry = poll_table;
529
        poll_entry->fd = server_fd;
530
        poll_entry->events = POLLIN;
531
        poll_entry++;
532

    
533
        poll_entry->fd = rtsp_server_fd;
534
        poll_entry->events = POLLIN;
535
        poll_entry++;
536

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

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

    
595
        cur_time = av_gettime() / 1000;
596

    
597
        if (need_to_start_children) {
598
            need_to_start_children = 0;
599
            start_children(first_feed);
600
        }
601

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

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

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

    
631
    if (is_rtsp) {
632
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
633
        c->state = RTSPSTATE_WAIT_REQUEST;
634
    } else {
635
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
636
        c->state = HTTPSTATE_WAIT_REQUEST;
637
    }
638
}
639

    
640
static void new_connection(int server_fd, int is_rtsp)
641
{
642
    struct sockaddr_in from_addr;
643
    int fd, len;
644
    HTTPContext *c = NULL;
645

    
646
    len = sizeof(from_addr);
647
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
648
                &len);
649
    if (fd < 0)
650
        return;
651
    fcntl(fd, F_SETFL, O_NONBLOCK);
652

    
653
    /* XXX: should output a warning page when coming
654
       close to the connection limit */
655
    if (nb_connections >= nb_max_connections)
656
        goto fail;
657

    
658
    /* add a new connection */
659
    c = av_mallocz(sizeof(HTTPContext));
660
    if (!c)
661
        goto fail;
662

    
663
    c->fd = fd;
664
    c->poll_entry = NULL;
665
    c->from_addr = from_addr;
666
    c->buffer_size = IOBUFFER_INIT_SIZE;
667
    c->buffer = av_malloc(c->buffer_size);
668
    if (!c->buffer)
669
        goto fail;
670

    
671
    c->next = first_http_ctx;
672
    first_http_ctx = c;
673
    nb_connections++;
674

    
675
    start_wait_request(c, is_rtsp);
676

    
677
    return;
678

    
679
 fail:
680
    if (c) {
681
        av_free(c->buffer);
682
        av_free(c);
683
    }
684
    closesocket(fd);
685
}
686

    
687
static void close_connection(HTTPContext *c)
688
{
689
    HTTPContext **cp, *c1;
690
    int i, nb_streams;
691
    AVFormatContext *ctx;
692
    URLContext *h;
693
    AVStream *st;
694

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

    
706
    /* remove references, if any (XXX: do it faster) */
707
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
708
        if (c1->rtsp_c == c)
709
            c1->rtsp_c = NULL;
710
    }
711

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

    
726
    /* free RTP output streams if any */
727
    nb_streams = 0;
728
    if (c->stream)
729
        nb_streams = c->stream->nb_streams;
730

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

    
743
    ctx = &c->fmt_ctx;
744

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

    
755
    for(i=0; i<ctx->nb_streams; i++)
756
        av_free(ctx->streams[i]) ;
757

    
758
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
759
        current_bandwidth -= c->stream->bandwidth;
760

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

    
767
    av_freep(&c->pb_buffer);
768
    av_freep(&c->packet_buffer);
769
    av_free(c->buffer);
770
    av_free(c);
771
    nb_connections--;
772
}
773

    
774
static int handle_connection(HTTPContext *c)
775
{
776
    int len, ret;
777

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

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

    
820
    case HTTPSTATE_SEND_HEADER:
821
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
822
            return -1;
823

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

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

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

    
886
        /* nothing to do, we'll be waken up by incoming feed packets */
887
        break;
888

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

    
948
static int extract_rates(char *rates, int ratelen, const char *request)
949
{
950
    const char *p;
951

    
952
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
953
        if (strncasecmp(p, "Pragma:", 7) == 0) {
954
            const char *q = p + 7;
955

    
956
            while (*q && *q != '\n' && isspace(*q))
957
                q++;
958

    
959
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
960
                int stream_no;
961
                int rate_no;
962

    
963
                q += 20;
964

    
965
                memset(rates, 0xff, ratelen);
966

    
967
                while (1) {
968
                    while (*q && *q != '\n' && *q != ':')
969
                        q++;
970

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

    
979
                    while (*q && *q != '\n' && !isspace(*q))
980
                        q++;
981
                }
982

    
983
                return 1;
984
            }
985
        }
986
        p = strchr(p, '\n');
987
        if (!p)
988
            break;
989

    
990
        p++;
991
    }
992

    
993
    return 0;
994
}
995

    
996
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
997
{
998
    int i;
999
    int best_bitrate = 100000000;
1000
    int best = -1;
1001

    
1002
    for (i = 0; i < feed->nb_streams; i++) {
1003
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1004

    
1005
        if (feed_codec->codec_id != codec->codec_id ||
1006
            feed_codec->sample_rate != codec->sample_rate ||
1007
            feed_codec->width != codec->width ||
1008
            feed_codec->height != codec->height) {
1009
            continue;
1010
        }
1011

    
1012
        /* Potential stream */
1013

    
1014
        /* We want the fastest stream less than bit_rate, or the slowest
1015
         * faster than bit_rate
1016
         */
1017

    
1018
        if (feed_codec->bit_rate <= bit_rate) {
1019
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1020
                best_bitrate = feed_codec->bit_rate;
1021
                best = i;
1022
            }
1023
        } else {
1024
            if (feed_codec->bit_rate < best_bitrate) {
1025
                best_bitrate = feed_codec->bit_rate;
1026
                best = i;
1027
            }
1028
        }
1029
    }
1030

    
1031
    return best;
1032
}
1033

    
1034
static int modify_current_stream(HTTPContext *c, char *rates)
1035
{
1036
    int i;
1037
    FFStream *req = c->stream;
1038
    int action_required = 0;
1039

    
1040
    /* Not much we can do for a feed */
1041
    if (!req->feed)
1042
        return 0;
1043

    
1044
    for (i = 0; i < req->nb_streams; i++) {
1045
        AVCodecContext *codec = req->streams[i]->codec;
1046

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

    
1065
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1066
            action_required = 1;
1067
    }
1068

    
1069
    return action_required;
1070
}
1071

    
1072

    
1073
static void do_switch_stream(HTTPContext *c, int i)
1074
{
1075
    if (c->switch_feed_streams[i] >= 0) {
1076
#ifdef PHILIP
1077
        c->feed_streams[i] = c->switch_feed_streams[i];
1078
#endif
1079

    
1080
        /* Now update the stream */
1081
    }
1082
    c->switch_feed_streams[i] = -1;
1083
}
1084

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

    
1096
static void get_word(char *buf, int buf_size, const char **pp)
1097
{
1098
    const char *p;
1099
    char *q;
1100

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

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

    
1121
    for (acl = stream->acl; acl; acl = acl->next) {
1122
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1123
            return (acl->action == IP_ALLOW) ? 1 : 0;
1124
        }
1125
        last_action = acl->action;
1126
    }
1127

    
1128
    /* Nothing matched, so return not the last action */
1129
    return (last_action == IP_DENY) ? 1 : 0;
1130
}
1131

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

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

    
1158
enum RedirType {
1159
    REDIR_NONE,
1160
    REDIR_ASX,
1161
    REDIR_RAM,
1162
    REDIR_ASF,
1163
    REDIR_RTSP,
1164
    REDIR_SDP,
1165
};
1166

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

    
1183
    p = c->buffer;
1184
    get_word(cmd, sizeof(cmd), (const char **)&p);
1185
    pstrcpy(c->method, sizeof(c->method), cmd);
1186

    
1187
    if (!strcmp(cmd, "GET"))
1188
        c->post = 0;
1189
    else if (!strcmp(cmd, "POST"))
1190
        c->post = 1;
1191
    else
1192
        return -1;
1193

    
1194
    get_word(url, sizeof(url), (const char **)&p);
1195
    pstrcpy(c->url, sizeof(c->url), url);
1196

    
1197
    get_word(protocol, sizeof(protocol), (const char **)&p);
1198
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1199
        return -1;
1200

    
1201
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1202

    
1203
    if (ffserver_debug)
1204
        http_log("New connection: %s %s\n", cmd, url);
1205

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

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

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

    
1228
        p++;
1229
    }
1230

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

    
1250
    // "redirect" / request to index.html
1251
    if (!strlen(filename))
1252
        pstrcpy(filename, sizeof(filename) - 1, "index.html");
1253

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

    
1265
    c->stream = stream;
1266
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1267
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1268

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

    
1280
        /* prepare output buffer */
1281
        c->buffer_ptr = c->buffer;
1282
        c->buffer_end = q;
1283
        c->state = HTTPSTATE_SEND_HEADER;
1284
        return 0;
1285
    }
1286

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

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

    
1303
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1304
        current_bandwidth += stream->bandwidth;
1305
    }
1306

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

    
1319
        /* prepare output buffer */
1320
        c->buffer_ptr = c->buffer;
1321
        c->buffer_end = q;
1322
        c->state = HTTPSTATE_SEND_HEADER;
1323
        return 0;
1324
    }
1325

    
1326
    if (redir_type != REDIR_NONE) {
1327
        char *hostinfo = 0;
1328

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

    
1338
            p++;
1339
        }
1340

    
1341
        if (hostinfo) {
1342
            char *eoh;
1343
            char hostbuf[260];
1344

    
1345
            while (isspace(*hostinfo))
1346
                hostinfo++;
1347

    
1348
            eoh = strchr(hostinfo, '\n');
1349
            if (eoh) {
1350
                if (eoh[-1] == '\r')
1351
                    eoh--;
1352

    
1353
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1354
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1355
                    hostbuf[eoh - hostinfo] = 0;
1356

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

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

    
1413
                            len = sizeof(my_addr);
1414
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1415

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

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

    
1442
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1443
        goto send_error;
1444
    }
1445

    
1446
    stream->conns_served++;
1447

    
1448
    /* XXX: add there authenticate and IP match */
1449

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

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

    
1471
                p++;
1472
            }
1473

    
1474
            if (logline) {
1475
                char *eol = strchr(logline, '\n');
1476

    
1477
                logline += 17;
1478

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

    
1487
#ifdef DEBUG_WMP
1488
            http_log("\nGot request:\n%s\n", c->buffer);
1489
#endif
1490

    
1491
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1492
                HTTPContext *wmpc;
1493

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

    
1500
                if (wmpc) {
1501
                    if (modify_current_stream(wmpc, ratebuf)) {
1502
                        wmpc->switch_pending = 1;
1503
                    }
1504
                }
1505
            }
1506

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

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

    
1526
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1527
        goto send_stats;
1528

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

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

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

    
1547
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1548

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

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

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

    
1584
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1585
{
1586
    static const char *suffix = " kMGTP";
1587
    const char *s;
1588

    
1589
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1590
    }
1591

    
1592
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1593
}
1594

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

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

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

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

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

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

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

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

    
1724
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1725
                {
1726
                    FILE *pid_stat;
1727
                    char ps_cmd[64];
1728

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

    
1734
                    pid_stat = popen(ps_cmd, "r");
1735
                    if (pid_stat) {
1736
                        char cpuperc[10];
1737
                        char cpuused[64];
1738

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

    
1749
                url_fprintf(pb, "<p>");
1750
            }
1751
            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");
1752

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

    
1759
                parameters[0] = 0;
1760

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

    
1779
        }
1780
        stream = stream->next;
1781
    }
1782

    
1783
#if 0
1784
    {
1785
        float avg;
1786
        AVCodecContext *enc;
1787
        char buf[1024];
1788

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

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

    
1813
    /* connection status */
1814
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1815

    
1816
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1817
                 nb_connections, nb_max_connections);
1818

    
1819
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1820
                 current_bandwidth, max_bandwidth);
1821

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

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

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

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

    
1868
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1869
    c->buffer_ptr = c->pb_buffer;
1870
    c->buffer_end = c->pb_buffer + len;
1871
}
1872

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

    
1879
    if (!st->codec->codec) {
1880
        codec = avcodec_find_decoder(st->codec->codec_id);
1881
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1882
            st->codec->parse_only = 1;
1883
            if (avcodec_open(st->codec, codec) < 0) {
1884
                st->codec->parse_only = 0;
1885
            }
1886
        }
1887
    }
1888
}
1889

    
1890
static int open_input_stream(HTTPContext *c, const char *info)
1891
{
1892
    char buf[128];
1893
    char input_filename[1024];
1894
    AVFormatContext *s;
1895
    int buf_size, i;
1896
    int64_t stream_pos;
1897

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

    
1924
#if 0
1925
    { time_t when = stream_pos / 1000000;
1926
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1927
    }
1928
#endif
1929

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

    
1938
    /* open each parser */
1939
    for(i=0;i<s->nb_streams;i++)
1940
        open_parser(s, i);
1941

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

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

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

    
1970
/* return the estimated time at which the current packet must be sent
1971
   (in us) */
1972
static int64_t get_packet_send_clock(HTTPContext *c)
1973
{
1974
    int bytes_left, bytes_sent, frame_bytes;
1975

    
1976
    frame_bytes = c->cur_frame_bytes;
1977
    if (frame_bytes <= 0) {
1978
        return c->cur_pts;
1979
    } else {
1980
        bytes_left = c->buffer_end - c->buffer_ptr;
1981
        bytes_sent = frame_bytes - bytes_left;
1982
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1983
    }
1984
}
1985

    
1986

    
1987
static int http_prepare_data(HTTPContext *c)
1988
{
1989
    int i, len, ret;
1990
    AVFormatContext *ctx;
1991

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

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

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

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

    
2039
        av_set_parameters(&c->fmt_ctx, NULL);
2040
        if (av_write_header(&c->fmt_ctx) < 0)
2041
            return -1;
2042

    
2043
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2044
        c->buffer_ptr = c->pb_buffer;
2045
        c->buffer_end = c->pb_buffer + len;
2046

    
2047
        c->state = HTTPSTATE_SEND_DATA;
2048
        c->last_packet_sent = 0;
2049
        break;
2050
    case HTTPSTATE_SEND_DATA:
2051
        /* find a new packet */
2052
        {
2053
            AVPacket pkt;
2054

    
2055
            /* read a packet from the input stream */
2056
            if (c->stream->feed) {
2057
                ffm_set_write_index(c->fmt_in,
2058
                                    c->stream->feed->feed_write_index,
2059
                                    c->stream->feed->feed_size);
2060
            }
2061

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

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

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

    
2194
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2195
                        c->cur_frame_bytes = len;
2196
                        c->buffer_ptr = c->pb_buffer;
2197
                        c->buffer_end = c->pb_buffer + len;
2198

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

    
2224
        c->last_packet_sent = 1;
2225
        break;
2226
    }
2227
    return 0;
2228
}
2229

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

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

    
2267
                c->data_count += len;
2268
                update_datarate(&c->datarate, c->data_count);
2269
                if (c->stream)
2270
                    c->stream->bytes_served += len;
2271

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

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

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

    
2356
static int http_start_receive_data(HTTPContext *c)
2357
{
2358
    int fd;
2359

    
2360
    if (c->stream->feed_opened)
2361
        return -1;
2362

    
2363
    /* Don't permit writing to this one */
2364
    if (c->stream->readonly)
2365
        return -1;
2366

    
2367
    /* open feed */
2368
    fd = open(c->stream->feed_filename, O_RDWR);
2369
    if (fd < 0)
2370
        return -1;
2371
    c->feed_fd = fd;
2372

    
2373
    c->stream->feed_write_index = ffm_read_write_index(fd);
2374
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2375
    lseek(fd, 0, SEEK_SET);
2376

    
2377
    /* init buffer input */
2378
    c->buffer_ptr = c->buffer;
2379
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2380
    c->stream->feed_opened = 1;
2381
    return 0;
2382
}
2383

    
2384
static int http_receive_data(HTTPContext *c)
2385
{
2386
    HTTPContext *c1;
2387

    
2388
    if (c->buffer_end > c->buffer_ptr) {
2389
        int len;
2390

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

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

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

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

    
2426
            feed->feed_write_index += FFM_PACKET_SIZE;
2427
            /* update file size */
2428
            if (feed->feed_write_index > c->stream->feed_size)
2429
                feed->feed_size = feed->feed_write_index;
2430

    
2431
            /* handle wrap around if max file size reached */
2432
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2433
                feed->feed_write_index = FFM_PACKET_SIZE;
2434

    
2435
            /* write index */
2436
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2437

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

    
2452
            memset(&s, 0, sizeof(s));
2453

    
2454
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2455
            pb->buf_end = c->buffer_end;        /* ?? */
2456
            pb->is_streamed = 1;
2457

    
2458
            /* use feed output format name to find corresponding input format */
2459
            fmt_in = av_find_input_format(feed->fmt->name);
2460
            if (!fmt_in)
2461
                goto fail;
2462

    
2463
            if (fmt_in->priv_data_size > 0) {
2464
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2465
                if (!s.priv_data)
2466
                    goto fail;
2467
            } else
2468
                s.priv_data = NULL;
2469

    
2470
            if (fmt_in->read_header(&s, 0) < 0) {
2471
                av_freep(&s.priv_data);
2472
                goto fail;
2473
            }
2474

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

    
2489
    return 0;
2490
 fail:
2491
    c->stream->feed_opened = 0;
2492
    close(c->feed_fd);
2493
    return -1;
2494
}
2495

    
2496
/********************************************************************/
2497
/* RTSP handling */
2498

    
2499
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2500
{
2501
    const char *str;
2502
    time_t ti;
2503
    char *p;
2504
    char buf2[32];
2505

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

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

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

    
2558
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2559
{
2560
    rtsp_reply_header(c, error_number);
2561
    url_fprintf(c->pb, "\r\n");
2562
}
2563

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

    
2575
    c->buffer_ptr[0] = '\0';
2576
    p = c->buffer;
2577

    
2578
    get_word(cmd, sizeof(cmd), &p);
2579
    get_word(url, sizeof(url), &p);
2580
    get_word(protocol, sizeof(protocol), &p);
2581

    
2582
    pstrcpy(c->method, sizeof(c->method), cmd);
2583
    pstrcpy(c->url, sizeof(c->url), url);
2584
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2585

    
2586
    c->pb = &pb1;
2587
    if (url_open_dyn_buf(c->pb) < 0) {
2588
        /* XXX: cannot do more */
2589
        c->pb = NULL; /* safety */
2590
        return -1;
2591
    }
2592

    
2593
    /* check version name */
2594
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2595
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2596
        goto the_end;
2597
    }
2598

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

    
2625
    /* handle sequence number */
2626
    c->seq = header->seq;
2627

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

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

    
2666
    if (url_open_dyn_buf(pb) < 0)
2667
        return -1;
2668

    
2669
    /* general media info */
2670

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

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

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

    
2765
    /* find which url is asked */
2766
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2767
    path = path1;
2768
    if (*path == '/')
2769
        path++;
2770

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

    
2781
 found:
2782
    /* prepare the media description in sdp format */
2783

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

    
2799
static HTTPContext *find_rtp_session(const char *session_id)
2800
{
2801
    HTTPContext *c;
2802

    
2803
    if (session_id[0] == '\0')
2804
        return NULL;
2805

    
2806
    for(c = first_http_ctx; c != NULL; c = c->next) {
2807
        if (!strcmp(c->session_id, session_id))
2808
            return c;
2809
    }
2810
    return NULL;
2811
}
2812

    
2813
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2814
{
2815
    RTSPTransportField *th;
2816
    int i;
2817

    
2818
    for(i=0;i<h->nb_transports;i++) {
2819
        th = &h->transports[i];
2820
        if (th->protocol == protocol)
2821
            return th;
2822
    }
2823
    return NULL;
2824
}
2825

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

    
2839
    /* find which url is asked */
2840
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2841
    path = path1;
2842
    if (*path == '/')
2843
        path++;
2844

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

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

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

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

    
2891
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2892
                                   th->protocol);
2893
        if (!rtp_c) {
2894
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2895
            return;
2896
        }
2897

    
2898
        /* open input stream */
2899
        if (open_input_stream(rtp_c, "") < 0) {
2900
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2901
            return;
2902
        }
2903
    }
2904

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

    
2912
    /* test if stream is already set up */
2913
    if (rtp_c->rtp_ctx[stream_index]) {
2914
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2915
        return;
2916
    }
2917

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

    
2926
    /* setup default options */
2927
    setup.transport_option[0] = '\0';
2928
    dest_addr = rtp_c->from_addr;
2929
    dest_addr.sin_port = htons(th->client_port_min);
2930

    
2931
    /* setup stream */
2932
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2933
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2934
        return;
2935
    }
2936

    
2937
    /* now everything is OK, so we can send the connection parameters */
2938
    rtsp_reply_header(c, RTSP_STATUS_OK);
2939
    /* session ID */
2940
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2941

    
2942
    switch(rtp_c->rtp_protocol) {
2943
    case RTSP_PROTOCOL_RTP_UDP:
2944
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2945
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2946
                    "client_port=%d-%d;server_port=%d-%d",
2947
                    th->client_port_min, th->client_port_min + 1,
2948
                    port, port + 1);
2949
        break;
2950
    case RTSP_PROTOCOL_RTP_TCP:
2951
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2952
                    stream_index * 2, stream_index * 2 + 1);
2953
        break;
2954
    default:
2955
        break;
2956
    }
2957
    if (setup.transport_option[0] != '\0') {
2958
        url_fprintf(c->pb, ";%s", setup.transport_option);
2959
    }
2960
    url_fprintf(c->pb, "\r\n");
2961

    
2962

    
2963
    url_fprintf(c->pb, "\r\n");
2964
}
2965

    
2966

    
2967
/* find an rtp connection by using the session ID. Check consistency
2968
   with filename */
2969
static HTTPContext *find_rtp_session_with_url(const char *url,
2970
                                              const char *session_id)
2971
{
2972
    HTTPContext *rtp_c;
2973
    char path1[1024];
2974
    const char *path;
2975
    char buf[1024];
2976
    int s;
2977

    
2978
    rtp_c = find_rtp_session(session_id);
2979
    if (!rtp_c)
2980
        return NULL;
2981

    
2982
    /* find which url is asked */
2983
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2984
    path = path1;
2985
    if (*path == '/')
2986
        path++;
2987
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2988
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2989
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2990
        rtp_c->stream->filename, s);
2991
      if(!strncmp(path, buf, sizeof(buf))) {
2992
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2993
        return rtp_c;
2994
      }
2995
    }
2996
    return NULL;
2997
}
2998

    
2999
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3000
{
3001
    HTTPContext *rtp_c;
3002

    
3003
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3004
    if (!rtp_c) {
3005
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3006
        return;
3007
    }
3008

    
3009
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3010
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3011
        rtp_c->state != HTTPSTATE_READY) {
3012
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3013
        return;
3014
    }
3015

    
3016
#if 0
3017
    /* XXX: seek in stream */
3018
    if (h->range_start != AV_NOPTS_VALUE) {
3019
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3020
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3021
    }
3022
#endif
3023

    
3024
    rtp_c->state = HTTPSTATE_SEND_DATA;
3025

    
3026
    /* now everything is OK, so we can send the connection parameters */
3027
    rtsp_reply_header(c, RTSP_STATUS_OK);
3028
    /* session ID */
3029
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3030
    url_fprintf(c->pb, "\r\n");
3031
}
3032

    
3033
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3034
{
3035
    HTTPContext *rtp_c;
3036

    
3037
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3038
    if (!rtp_c) {
3039
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3040
        return;
3041
    }
3042

    
3043
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3044
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3045
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3046
        return;
3047
    }
3048

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

    
3058
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3059
{
3060
    HTTPContext *rtp_c;
3061
    char session_id[32];
3062

    
3063
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3064
    if (!rtp_c) {
3065
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3066
        return;
3067
    }
3068

    
3069
    pstrcpy(session_id, sizeof(session_id), rtp_c->session_id);
3070

    
3071
    /* abort the session */
3072
    close_connection(rtp_c);
3073

    
3074
    /* now everything is OK, so we can send the connection parameters */
3075
    rtsp_reply_header(c, RTSP_STATUS_OK);
3076
    /* session ID */
3077
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3078
    url_fprintf(c->pb, "\r\n");
3079
}
3080

    
3081

    
3082
/********************************************************************/
3083
/* RTP handling */
3084

    
3085
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3086
                                       FFStream *stream, const char *session_id,
3087
                                       enum RTSPProtocol rtp_protocol)
3088
{
3089
    HTTPContext *c = NULL;
3090
    const char *proto_str;
3091

    
3092
    /* XXX: should output a warning page when coming
3093
       close to the connection limit */
3094
    if (nb_connections >= nb_max_connections)
3095
        goto fail;
3096

    
3097
    /* add a new connection */
3098
    c = av_mallocz(sizeof(HTTPContext));
3099
    if (!c)
3100
        goto fail;
3101

    
3102
    c->fd = -1;
3103
    c->poll_entry = NULL;
3104
    c->from_addr = *from_addr;
3105
    c->buffer_size = IOBUFFER_INIT_SIZE;
3106
    c->buffer = av_malloc(c->buffer_size);
3107
    if (!c->buffer)
3108
        goto fail;
3109
    nb_connections++;
3110
    c->stream = stream;
3111
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3112
    c->state = HTTPSTATE_READY;
3113
    c->is_packetized = 1;
3114
    c->rtp_protocol = rtp_protocol;
3115

    
3116
    /* protocol is shown in statistics */
3117
    switch(c->rtp_protocol) {
3118
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3119
        proto_str = "MCAST";
3120
        break;
3121
    case RTSP_PROTOCOL_RTP_UDP:
3122
        proto_str = "UDP";
3123
        break;
3124
    case RTSP_PROTOCOL_RTP_TCP:
3125
        proto_str = "TCP";
3126
        break;
3127
    default:
3128
        proto_str = "???";
3129
        break;
3130
    }
3131
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3132
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3133

    
3134
    current_bandwidth += stream->bandwidth;
3135

    
3136
    c->next = first_http_ctx;
3137
    first_http_ctx = c;
3138
    return c;
3139

    
3140
 fail:
3141
    if (c) {
3142
        av_free(c->buffer);
3143
        av_free(c);
3144
    }
3145
    return NULL;
3146
}
3147

    
3148
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3149
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3150
   used. */
3151
static int rtp_new_av_stream(HTTPContext *c,
3152
                             int stream_index, struct sockaddr_in *dest_addr,
3153
                             HTTPContext *rtsp_c)
3154
{
3155
    AVFormatContext *ctx;
3156
    AVStream *st;
3157
    char *ipaddr;
3158
    URLContext *h;
3159
    uint8_t *dummy_buf;
3160
    char buf2[32];
3161
    int max_packet_size;
3162

    
3163
    /* now we can open the relevant output stream */
3164
    ctx = av_alloc_format_context();
3165
    if (!ctx)
3166
        return -1;
3167
    ctx->oformat = &rtp_muxer;
3168

    
3169
    st = av_mallocz(sizeof(AVStream));
3170
    if (!st)
3171
        goto fail;
3172
    st->codec= avcodec_alloc_context();
3173
    ctx->nb_streams = 1;
3174
    ctx->streams[0] = st;
3175

    
3176
    if (!c->stream->feed ||
3177
        c->stream->feed == c->stream) {
3178
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3179
    } else {
3180
        memcpy(st,
3181
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3182
               sizeof(AVStream));
3183
    }
3184
    st->priv_data = NULL;
3185

    
3186
    /* build destination RTP address */
3187
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3188

    
3189
    switch(c->rtp_protocol) {
3190
    case RTSP_PROTOCOL_RTP_UDP:
3191
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3192
        /* RTP/UDP case */
3193

    
3194
        /* XXX: also pass as parameter to function ? */
3195
        if (c->stream->is_multicast) {
3196
            int ttl;
3197
            ttl = c->stream->multicast_ttl;
3198
            if (!ttl)
3199
                ttl = 16;
3200
            snprintf(ctx->filename, sizeof(ctx->filename),
3201
                     "rtp://%s:%d?multicast=1&ttl=%d",
3202
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3203
        } else {
3204
            snprintf(ctx->filename, sizeof(ctx->filename),
3205
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3206
        }
3207

    
3208
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3209
            goto fail;
3210
        c->rtp_handles[stream_index] = h;
3211
        max_packet_size = url_get_max_packet_size(h);
3212
        break;
3213
    case RTSP_PROTOCOL_RTP_TCP:
3214
        /* RTP/TCP case */
3215
        c->rtsp_c = rtsp_c;
3216
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3217
        break;
3218
    default:
3219
        goto fail;
3220
    }
3221

    
3222
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3223
             ipaddr, ntohs(dest_addr->sin_port),
3224
             ctime1(buf2),
3225
             c->stream->filename, stream_index, c->protocol);
3226

    
3227
    /* normally, no packets should be output here, but the packet size may be checked */
3228
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3229
        /* XXX: close stream */
3230
        goto fail;
3231
    }
3232
    av_set_parameters(ctx, NULL);
3233
    if (av_write_header(ctx) < 0) {
3234
    fail:
3235
        if (h)
3236
            url_close(h);
3237
        av_free(ctx);
3238
        return -1;
3239
    }
3240
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3241
    av_free(dummy_buf);
3242

    
3243
    c->rtp_ctx[stream_index] = ctx;
3244
    return 0;
3245
}
3246

    
3247
/********************************************************************/
3248
/* ffserver initialization */
3249

    
3250
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3251
{
3252
    AVStream *fst;
3253

    
3254
    fst = av_mallocz(sizeof(AVStream));
3255
    if (!fst)
3256
        return NULL;
3257
    fst->codec= avcodec_alloc_context();
3258
    fst->priv_data = av_mallocz(sizeof(FeedData));
3259
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3260
    fst->codec->coded_frame = &dummy_frame;
3261
    fst->index = stream->nb_streams;
3262
    av_set_pts_info(fst, 33, 1, 90000);
3263
    stream->streams[stream->nb_streams++] = fst;
3264
    return fst;
3265
}
3266

    
3267
/* return the stream number in the feed */
3268
static int add_av_stream(FFStream *feed, AVStream *st)
3269
{
3270
    AVStream *fst;
3271
    AVCodecContext *av, *av1;
3272
    int i;
3273

    
3274
    av = st->codec;
3275
    for(i=0;i<feed->nb_streams;i++) {
3276
        st = feed->streams[i];
3277
        av1 = st->codec;
3278
        if (av1->codec_id == av->codec_id &&
3279
            av1->codec_type == av->codec_type &&
3280
            av1->bit_rate == av->bit_rate) {
3281

    
3282
            switch(av->codec_type) {
3283
            case CODEC_TYPE_AUDIO:
3284
                if (av1->channels == av->channels &&
3285
                    av1->sample_rate == av->sample_rate)
3286
                    goto found;
3287
                break;
3288
            case CODEC_TYPE_VIDEO:
3289
                if (av1->width == av->width &&
3290
                    av1->height == av->height &&
3291
                    av1->time_base.den == av->time_base.den &&
3292
                    av1->time_base.num == av->time_base.num &&
3293
                    av1->gop_size == av->gop_size)
3294
                    goto found;
3295
                break;
3296
            default:
3297
                av_abort();
3298
            }
3299
        }
3300
    }
3301

    
3302
    fst = add_av_stream1(feed, av);
3303
    if (!fst)
3304
        return -1;
3305
    return feed->nb_streams - 1;
3306
 found:
3307
    return i;
3308
}
3309

    
3310
static void remove_stream(FFStream *stream)
3311
{
3312
    FFStream **ps;
3313
    ps = &first_stream;
3314
    while (*ps != NULL) {
3315
        if (*ps == stream) {
3316
            *ps = (*ps)->next;
3317
        } else {
3318
            ps = &(*ps)->next;
3319
        }
3320
    }
3321
}
3322

    
3323
/* specific mpeg4 handling : we extract the raw parameters */
3324
static void extract_mpeg4_header(AVFormatContext *infile)
3325
{
3326
    int mpeg4_count, i, size;
3327
    AVPacket pkt;
3328
    AVStream *st;
3329
    const uint8_t *p;
3330

    
3331
    mpeg4_count = 0;
3332
    for(i=0;i<infile->nb_streams;i++) {
3333
        st = infile->streams[i];
3334
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3335
            st->codec->extradata_size == 0) {
3336
            mpeg4_count++;
3337
        }
3338
    }
3339
    if (!mpeg4_count)
3340
        return;
3341

    
3342
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3343
    while (mpeg4_count > 0) {
3344
        if (av_read_packet(infile, &pkt) < 0)
3345
            break;
3346
        st = infile->streams[pkt.stream_index];
3347
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3348
            st->codec->extradata_size == 0) {
3349
            av_freep(&st->codec->extradata);
3350
            /* fill extradata with the header */
3351
            /* XXX: we make hard suppositions here ! */
3352
            p = pkt.data;
3353
            while (p < pkt.data + pkt.size - 4) {
3354
                /* stop when vop header is found */
3355
                if (p[0] == 0x00 && p[1] == 0x00 &&
3356
                    p[2] == 0x01 && p[3] == 0xb6) {
3357
                    size = p - pkt.data;
3358
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3359
                    st->codec->extradata = av_malloc(size);
3360
                    st->codec->extradata_size = size;
3361
                    memcpy(st->codec->extradata, pkt.data, size);
3362
                    break;
3363
                }
3364
                p++;
3365
            }
3366
            mpeg4_count--;
3367
        }
3368
        av_free_packet(&pkt);
3369
    }
3370
}
3371

    
3372
/* compute the needed AVStream for each file */
3373
static void build_file_streams(void)
3374
{
3375
    FFStream *stream, *stream_next;
3376
    AVFormatContext *infile;
3377
    int i;
3378

    
3379
    /* gather all streams */
3380
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3381
        stream_next = stream->next;
3382
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3383
            !stream->feed) {
3384
            /* the stream comes from a file */
3385
            /* try to open the file */
3386
            /* open stream */
3387
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3388
            if (stream->fmt == &rtp_muxer) {
3389
                /* specific case : if transport stream output to RTP,
3390
                   we use a raw transport stream reader */
3391
                stream->ap_in->mpeg2ts_raw = 1;
3392
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3393
            }
3394

    
3395
            if (av_open_input_file(&infile, stream->feed_filename,
3396
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3397
                http_log("%s not found", stream->feed_filename);
3398
                /* remove stream (no need to spend more time on it) */
3399
            fail:
3400
                remove_stream(stream);
3401
            } else {
3402
                /* find all the AVStreams inside and reference them in
3403
                   'stream' */
3404
                if (av_find_stream_info(infile) < 0) {
3405
                    http_log("Could not find codec parameters from '%s'",
3406
                             stream->feed_filename);
3407
                    av_close_input_file(infile);
3408
                    goto fail;
3409
                }
3410
                extract_mpeg4_header(infile);
3411

    
3412
                for(i=0;i<infile->nb_streams;i++) {
3413
                    add_av_stream1(stream, infile->streams[i]->codec);
3414
                }
3415
                av_close_input_file(infile);
3416
            }
3417
        }
3418
    }
3419
}
3420

    
3421
/* compute the needed AVStream for each feed */
3422
static void build_feed_streams(void)
3423
{
3424
    FFStream *stream, *feed;
3425
    int i;
3426

    
3427
    /* gather all streams */
3428
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3429
        feed = stream->feed;
3430
        if (feed) {
3431
            if (!stream->is_feed) {
3432
                /* we handle a stream coming from a feed */
3433
                for(i=0;i<stream->nb_streams;i++) {
3434
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3435
                }
3436
            }
3437
        }
3438
    }
3439

    
3440
    /* gather all streams */
3441
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3442
        feed = stream->feed;
3443
        if (feed) {
3444
            if (stream->is_feed) {
3445
                for(i=0;i<stream->nb_streams;i++) {
3446
                    stream->feed_streams[i] = i;
3447
                }
3448
            }
3449
        }
3450
    }
3451

    
3452
    /* create feed files if needed */
3453
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3454
        int fd;
3455

    
3456
        if (url_exist(feed->feed_filename)) {
3457
            /* See if it matches */
3458
            AVFormatContext *s;
3459
            int matches = 0;
3460

    
3461
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3462
                /* Now see if it matches */
3463
                if (s->nb_streams == feed->nb_streams) {
3464
                    matches = 1;
3465
                    for(i=0;i<s->nb_streams;i++) {
3466
                        AVStream *sf, *ss;
3467
                        sf = feed->streams[i];
3468
                        ss = s->streams[i];
3469

    
3470
                        if (sf->index != ss->index ||
3471
                            sf->id != ss->id) {
3472
                            printf("Index & Id do not match for stream %d (%s)\n",
3473
                                   i, feed->feed_filename);
3474
                            matches = 0;
3475
                        } else {
3476
                            AVCodecContext *ccf, *ccs;
3477

    
3478
                            ccf = sf->codec;
3479
                            ccs = ss->codec;
3480
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3481

    
3482
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3483
                                printf("Codecs do not match for stream %d\n", i);
3484
                                matches = 0;
3485
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3486
                                printf("Codec bitrates do not match for stream %d\n", i);
3487
                                matches = 0;
3488
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3489
                                if (CHECK_CODEC(time_base.den) ||
3490
                                    CHECK_CODEC(time_base.num) ||
3491
                                    CHECK_CODEC(width) ||
3492
                                    CHECK_CODEC(height)) {
3493
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3494
                                    matches = 0;
3495
                                }
3496
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3497
                                if (CHECK_CODEC(sample_rate) ||
3498
                                    CHECK_CODEC(channels) ||
3499
                                    CHECK_CODEC(frame_size)) {
3500
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3501
                                    matches = 0;
3502
                                }
3503
                            } else {
3504
                                printf("Unknown codec type\n");
3505
                                matches = 0;
3506
                            }
3507
                        }
3508
                        if (!matches) {
3509
                            break;
3510
                        }
3511
                    }
3512
                } else {
3513
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3514
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3515
                }
3516

    
3517
                av_close_input_file(s);
3518
            } else {
3519
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3520
                        feed->feed_filename);
3521
            }
3522
            if (!matches) {
3523
                if (feed->readonly) {
3524
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3525
                        feed->feed_filename);
3526
                    exit(1);
3527
                }
3528
                unlink(feed->feed_filename);
3529
            }
3530
        }
3531
        if (!url_exist(feed->feed_filename)) {
3532
            AVFormatContext s1, *s = &s1;
3533

    
3534
            if (feed->readonly) {
3535
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3536
                    feed->feed_filename);
3537
                exit(1);
3538
            }
3539

    
3540
            /* only write the header of the ffm file */
3541
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3542
                fprintf(stderr, "Could not open output feed file '%s'\n",
3543
                        feed->feed_filename);
3544
                exit(1);
3545
            }
3546
            s->oformat = feed->fmt;
3547
            s->nb_streams = feed->nb_streams;
3548
            for(i=0;i<s->nb_streams;i++) {
3549
                AVStream *st;
3550
                st = feed->streams[i];
3551
                s->streams[i] = st;
3552
            }
3553
            av_set_parameters(s, NULL);
3554
            if (av_write_header(s) < 0) {
3555
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3556
                exit(1);
3557
            }
3558
            /* XXX: need better api */
3559
            av_freep(&s->priv_data);
3560
            url_fclose(&s->pb);
3561
        }
3562
        /* get feed size and write index */
3563
        fd = open(feed->feed_filename, O_RDONLY);
3564
        if (fd < 0) {
3565
            fprintf(stderr, "Could not open output feed file '%s'\n",
3566
                    feed->feed_filename);
3567
            exit(1);
3568
        }
3569

    
3570
        feed->feed_write_index = ffm_read_write_index(fd);
3571
        feed->feed_size = lseek(fd, 0, SEEK_END);
3572
        /* ensure that we do not wrap before the end of file */
3573
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3574
            feed->feed_max_size = feed->feed_size;
3575

    
3576
        close(fd);
3577
    }
3578
}
3579

    
3580
/* compute the bandwidth used by each stream */
3581
static void compute_bandwidth(void)
3582
{
3583
    int bandwidth, i;
3584
    FFStream *stream;
3585

    
3586
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3587
        bandwidth = 0;
3588
        for(i=0;i<stream->nb_streams;i++) {
3589
            AVStream *st = stream->streams[i];
3590
            switch(st->codec->codec_type) {
3591
            case CODEC_TYPE_AUDIO:
3592
            case CODEC_TYPE_VIDEO:
3593
                bandwidth += st->codec->bit_rate;
3594
                break;
3595
            default:
3596
                break;
3597
            }
3598
        }
3599
        stream->bandwidth = (bandwidth + 999) / 1000;
3600
    }
3601
}
3602

    
3603
static void get_arg(char *buf, int buf_size, const char **pp)
3604
{
3605
    const char *p;
3606
    char *q;
3607
    int quote;
3608

    
3609
    p = *pp;
3610
    while (isspace(*p)) p++;
3611
    q = buf;
3612
    quote = 0;
3613
    if (*p == '\"' || *p == '\'')
3614
        quote = *p++;
3615
    for(;;) {
3616
        if (quote) {
3617
            if (*p == quote)
3618
                break;
3619
        } else {
3620
            if (isspace(*p))
3621
                break;
3622
        }
3623
        if (*p == '\0')
3624
            break;
3625
        if ((q - buf) < buf_size - 1)
3626
            *q++ = *p;
3627
        p++;
3628
    }
3629
    *q = '\0';
3630
    if (quote && *p == quote)
3631
        p++;
3632
    *pp = p;
3633
}
3634

    
3635
/* add a codec and set the default parameters */
3636
static void add_codec(FFStream *stream, AVCodecContext *av)
3637
{
3638
    AVStream *st;
3639

    
3640
    /* compute default parameters */
3641
    switch(av->codec_type) {
3642
    case CODEC_TYPE_AUDIO:
3643
        if (av->bit_rate == 0)
3644
            av->bit_rate = 64000;
3645
        if (av->sample_rate == 0)
3646
            av->sample_rate = 22050;
3647
        if (av->channels == 0)
3648
            av->channels = 1;
3649
        break;
3650
    case CODEC_TYPE_VIDEO:
3651
        if (av->bit_rate == 0)
3652
            av->bit_rate = 64000;
3653
        if (av->time_base.num == 0){
3654
            av->time_base.den = 5;
3655
            av->time_base.num = 1;
3656
        }
3657
        if (av->width == 0 || av->height == 0) {
3658
            av->width = 160;
3659
            av->height = 128;
3660
        }
3661
        /* Bitrate tolerance is less for streaming */
3662
        if (av->bit_rate_tolerance == 0)
3663
            av->bit_rate_tolerance = av->bit_rate / 4;
3664
        if (av->qmin == 0)
3665
            av->qmin = 3;
3666
        if (av->qmax == 0)
3667
            av->qmax = 31;
3668
        if (av->max_qdiff == 0)
3669
            av->max_qdiff = 3;
3670
        av->qcompress = 0.5;
3671
        av->qblur = 0.5;
3672

    
3673
        if (!av->nsse_weight)
3674
            av->nsse_weight = 8;
3675

    
3676
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3677
        av->me_method = ME_EPZS;
3678
        av->rc_buffer_aggressivity = 1.0;
3679

    
3680
        if (!av->rc_eq)
3681
            av->rc_eq = "tex^qComp";
3682
        if (!av->i_quant_factor)
3683
            av->i_quant_factor = -0.8;
3684
        if (!av->b_quant_factor)
3685
            av->b_quant_factor = 1.25;
3686
        if (!av->b_quant_offset)
3687
            av->b_quant_offset = 1.25;
3688
        if (!av->rc_max_rate)
3689
            av->rc_max_rate = av->bit_rate * 2;
3690

    
3691
        if (av->rc_max_rate && !av->rc_buffer_size) {
3692
            av->rc_buffer_size = av->rc_max_rate;
3693
        }
3694

    
3695

    
3696
        break;
3697
    default:
3698
        av_abort();
3699
    }
3700

    
3701
    st = av_mallocz(sizeof(AVStream));
3702
    if (!st)
3703
        return;
3704
    st->codec = avcodec_alloc_context();
3705
    stream->streams[stream->nb_streams++] = st;
3706
    memcpy(st->codec, av, sizeof(AVCodecContext));
3707
}
3708

    
3709
static int opt_audio_codec(const char *arg)
3710
{
3711
    AVCodec *p;
3712

    
3713
    p = first_avcodec;
3714
    while (p) {
3715
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3716
            break;
3717
        p = p->next;
3718
    }
3719
    if (p == NULL) {
3720
        return CODEC_ID_NONE;
3721
    }
3722

    
3723
    return p->id;
3724
}
3725

    
3726
static int opt_video_codec(const char *arg)
3727
{
3728
    AVCodec *p;
3729

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

    
3740
    return p->id;
3741
}
3742

    
3743
/* simplistic plugin support */
3744

    
3745
#ifdef HAVE_DLOPEN
3746
static void load_module(const char *filename)
3747
{
3748
    void *dll;
3749
    void (*init_func)(void);
3750
    dll = dlopen(filename, RTLD_NOW);
3751
    if (!dll) {
3752
        fprintf(stderr, "Could not load module '%s' - %s\n",
3753
                filename, dlerror());
3754
        return;
3755
    }
3756

    
3757
    init_func = dlsym(dll, "ffserver_module_init");
3758
    if (!init_func) {
3759
        fprintf(stderr,
3760
                "%s: init function 'ffserver_module_init()' not found\n",
3761
                filename);
3762
        dlclose(dll);
3763
    }
3764

    
3765
    init_func();
3766
}
3767
#endif
3768

    
3769
static int parse_ffconfig(const char *filename)
3770
{
3771
    FILE *f;
3772
    char line[1024];
3773
    char cmd[64];
3774
    char arg[1024];
3775
    const char *p;
3776
    int val, errors, line_num;
3777
    FFStream **last_stream, *stream, *redirect;
3778
    FFStream **last_feed, *feed;
3779
    AVCodecContext audio_enc, video_enc;
3780
    int audio_id, video_id;
3781

    
3782
    f = fopen(filename, "r");
3783
    if (!f) {
3784
        perror(filename);
3785
        return -1;
3786
    }
3787

    
3788
    errors = 0;
3789
    line_num = 0;
3790
    first_stream = NULL;
3791
    last_stream = &first_stream;
3792
    first_feed = NULL;
3793
    last_feed = &first_feed;
3794
    stream = NULL;
3795
    feed = NULL;
3796
    redirect = NULL;
3797
    audio_id = CODEC_ID_NONE;
3798
    video_id = CODEC_ID_NONE;
3799
    for(;;) {
3800
        if (fgets(line, sizeof(line), f) == NULL)
3801
            break;
3802
        line_num++;
3803
        p = line;
3804
        while (isspace(*p))
3805
            p++;
3806
        if (*p == '\0' || *p == '#')
3807
            continue;
3808

    
3809
        get_arg(cmd, sizeof(cmd), &p);
3810

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

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

    
3899
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3900

    
3901
                for (i = 0; i < 62; i++) {
3902
                    get_arg(arg, sizeof(arg), &p);
3903
                    if (!arg[0])
3904
                        break;
3905

    
3906
                    feed->child_argv[i] = av_strdup(arg);
3907
                }
3908

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

    
3911
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3912
                    "http://%s:%d/%s",
3913
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3914
                    inet_ntoa(my_http_addr.sin_addr),
3915
                    ntohs(my_http_addr.sin_port), feed->filename);
3916

    
3917
                if (ffserver_debug)
3918
                {
3919
                    int j;
3920
                    fprintf(stdout, "Launch commandline: ");
3921
                    for (j = 0; j <= i; j++)
3922
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3923
                    fprintf(stdout, "\n");
3924
                }
3925
            }
3926
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3927
            if (feed) {
3928
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3929
                feed->readonly = 1;
3930
            } else if (stream) {
3931
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3932
            }
3933
        } else if (!strcasecmp(cmd, "File")) {
3934
            if (feed) {
3935
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3936
            } else if (stream) {
3937
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3938
            }
3939
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3940
            if (feed) {
3941
                const char *p1;
3942
                double fsize;
3943

    
3944
                get_arg(arg, sizeof(arg), &p);
3945
                p1 = arg;
3946
                fsize = strtod(p1, (char **)&p1);
3947
                switch(toupper(*p1)) {
3948
                case 'K':
3949
                    fsize *= 1024;
3950
                    break;
3951
                case 'M':
3952
                    fsize *= 1024 * 1024;
3953
                    break;
3954
                case 'G':
3955
                    fsize *= 1024 * 1024 * 1024;
3956
                    break;
3957
                }
3958
                feed->feed_max_size = (int64_t)fsize;
3959
            }
3960
        } else if (!strcasecmp(cmd, "</Feed>")) {
3961
            if (!feed) {
3962
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3963
                        filename, line_num);
3964
                errors++;
3965
            }
3966
            feed = NULL;
3967
        } else if (!strcasecmp(cmd, "<Stream")) {
3968
            /*********************************************/
3969
            /* Stream related options */
3970
            char *q;
3971
            if (stream || feed) {
3972
                fprintf(stderr, "%s:%d: Already in a tag\n",
3973
                        filename, line_num);
3974
            } else {
3975
                stream = av_mallocz(sizeof(FFStream));
3976
                *last_stream = stream;
3977
                last_stream = &stream->next;
3978

    
3979
                get_arg(stream->filename, sizeof(stream->filename), &p);
3980
                q = strrchr(stream->filename, '>');
3981
                if (*q)
3982
                    *q = '\0';
3983
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3984
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3985
                memset(&video_enc, 0, sizeof(AVCodecContext));
3986
                audio_id = CODEC_ID_NONE;
3987
                video_id = CODEC_ID_NONE;
3988
                if (stream->fmt) {
3989
                    audio_id = stream->fmt->audio_codec;
3990
                    video_id = stream->fmt->video_codec;
3991
                }
3992
            }
3993
        } else if (!strcasecmp(cmd, "Feed")) {
3994
            get_arg(arg, sizeof(arg), &p);
3995
            if (stream) {
3996
                FFStream *sfeed;
3997

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

    
4117
                get_arg(arg, sizeof(arg), &p);
4118

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

    
4268
            get_arg(arg, sizeof(arg), &p);
4269
            if (strcasecmp(arg, "allow") == 0) {
4270
                acl.action = IP_ALLOW;
4271
            } else if (strcasecmp(arg, "deny") == 0) {
4272
                acl.action = IP_DENY;
4273
            } else {
4274
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4275
                        filename, line_num, arg);
4276
                errors++;
4277
            }
4278

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

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

    
4289
            get_arg(arg, sizeof(arg), &p);
4290

    
4291
            if (arg[0]) {
4292
                if (resolve_host(&acl.last, arg) != 0) {
4293
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4294
                            filename, line_num, arg);
4295
                    errors++;
4296
                }
4297
            }
4298

    
4299
            if (!errors) {
4300
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4301
                IPAddressACL **naclp = 0;
4302

    
4303
                acl.next = 0;
4304
                *nacl = acl;
4305

    
4306
                if (stream) {
4307
                    naclp = &stream->acl;
4308
                } else if (feed) {
4309
                    naclp = &feed->acl;
4310
                } else {
4311
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4312
                            filename, line_num);
4313
                    errors++;
4314
                }
4315

    
4316
                if (naclp) {
4317
                    while (*naclp)
4318
                        naclp = &(*naclp)->next;
4319

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

    
4385
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4386
                q = strrchr(redirect->filename, '>');
4387
                if (*q)
4388
                    *q = '\0';
4389
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4390
            }
4391
        } else if (!strcasecmp(cmd, "URL")) {
4392
            if (redirect) {
4393
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4394
            }
4395
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4396
            if (!redirect) {
4397
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4398
                        filename, line_num);
4399
                errors++;
4400
            }
4401
            if (!redirect->feed_filename[0]) {
4402
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4403
                        filename, line_num);
4404
                errors++;
4405
            }
4406
            redirect = NULL;
4407
        } else if (!strcasecmp(cmd, "LoadModule")) {
4408
            get_arg(arg, sizeof(arg), &p);
4409
#ifdef HAVE_DLOPEN
4410
            load_module(arg);
4411
#else
4412
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4413
                    filename, line_num, arg);
4414
            errors++;
4415
#endif
4416
        } else {
4417
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4418
                    filename, line_num, cmd);
4419
            errors++;
4420
        }
4421
    }
4422

    
4423
    fclose(f);
4424
    if (errors)
4425
        return -1;
4426
    else
4427
        return 0;
4428
}
4429

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

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

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

    
4467
static void handle_child_exit(int sig)
4468
{
4469
    pid_t pid;
4470
    int status;
4471

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

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

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

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

    
4490
    need_to_start_children = 1;
4491
}
4492

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

    
4499
    av_register_all();
4500

    
4501
    config_filename = "/etc/ffserver.conf";
4502

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

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

    
4534
    putenv("http_proxy");               /* Kill the http_proxy */
4535

    
4536
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4537

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

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

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

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

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

    
4563
    build_file_streams();
4564

    
4565
    build_feed_streams();
4566

    
4567
    compute_bandwidth();
4568

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

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

    
4595
    /* signal init */
4596
    signal(SIGPIPE, SIG_IGN);
4597

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

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

    
4611
    return 0;
4612
}