Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 33f5e2ec

History | View | Annotate | Download (150 KB)

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

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

    
42
#include "ffserver.h"
43

    
44
/* maximum number of simultaneous HTTP connections */
45
#define HTTP_MAX_CONNECTIONS 2000
46

    
47
enum HTTPState {
48
    HTTPSTATE_WAIT_REQUEST,
49
    HTTPSTATE_SEND_HEADER,
50
    HTTPSTATE_SEND_DATA_HEADER,
51
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
52
    HTTPSTATE_SEND_DATA_TRAILER,
53
    HTTPSTATE_RECEIVE_DATA,
54
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
55
    HTTPSTATE_READY,
56

    
57
    RTSPSTATE_WAIT_REQUEST,
58
    RTSPSTATE_SEND_REPLY,
59
    RTSPSTATE_SEND_PACKET,
60
};
61

    
62
const char *http_state[] = {
63
    "HTTP_WAIT_REQUEST",
64
    "HTTP_SEND_HEADER",
65

    
66
    "SEND_DATA_HEADER",
67
    "SEND_DATA",
68
    "SEND_DATA_TRAILER",
69
    "RECEIVE_DATA",
70
    "WAIT_FEED",
71
    "READY",
72

    
73
    "RTSP_WAIT_REQUEST",
74
    "RTSP_SEND_REPLY",
75
    "RTSP_SEND_PACKET",
76
};
77

    
78
#define IOBUFFER_INIT_SIZE 8192
79

    
80
/* coef for exponential mean for bitrate estimation in statistics */
81
#define AVG_COEF 0.9
82

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

    
87
#define SYNC_TIMEOUT (10 * 1000)
88

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

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

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

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

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

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

    
157
static AVFrame dummy_frame;
158

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

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

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

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

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

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

    
232
struct sockaddr_in my_http_addr;
233
struct sockaddr_in my_rtsp_addr;
234

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

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

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

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

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

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

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

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

    
281
static int nb_max_connections;
282
static int nb_connections;
283

    
284
static int max_bandwidth;
285
static int current_bandwidth;
286

    
287
static long cur_time;           // Making this global saves on passing it around everywhere
288

    
289
static long gettime_ms(void)
290
{
291
    struct timeval tv;
292

    
293
    gettimeofday(&tv,NULL);
294
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
295
}
296

    
297
static FILE *logfile = NULL;
298

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

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

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

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

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

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

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

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

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

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

    
362

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

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

    
372
            feed->pid = fork();
373

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

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

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

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

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

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

    
411
                signal(SIGPIPE, SIG_DFL);
412

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

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

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

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

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

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

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

    
450
    return server_fd;
451
}
452

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

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

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

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

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

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

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

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

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

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

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

    
525
    start_children(first_feed);
526

    
527
    first_http_ctx = NULL;
528
    nb_connections = 0;
529

    
530
    start_multicast();
531

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

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

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

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

    
600
        cur_time = gettime_ms();
601

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

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

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

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

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

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

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

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

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

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

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

    
680
    start_wait_request(c, is_rtsp);
681

    
682
    return;
683

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

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

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

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

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

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

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

    
748
    ctx = &c->fmt_ctx;
749

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

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

    
763
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
764
        current_bandwidth -= c->stream->bandwidth;
765
    av_freep(&c->pb_buffer);
766
    av_freep(&c->packet_buffer);
767
    av_free(c->buffer);
768
    av_free(c);
769
    nb_connections--;
770
}
771

    
772
static int handle_connection(HTTPContext *c)
773
{
774
    int len, ret;
775

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

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

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

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

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

    
860
            /* no need to read if no events */
861
            if (!(c->poll_entry->revents & POLLOUT))
862
                return 0;
863
        }
864
        if (http_send_data(c) < 0)
865
            return -1;
866
        break;
867
    case HTTPSTATE_RECEIVE_DATA:
868
        /* no need to read if no events */
869
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
870
            return -1;
871
        if (!(c->poll_entry->revents & POLLIN))
872
            return 0;
873
        if (http_receive_data(c) < 0)
874
            return -1;
875
        break;
876
    case HTTPSTATE_WAIT_FEED:
877
        /* no need to read if no events */
878
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
879
            return -1;
880

    
881
        /* nothing to do, we'll be waken up by incoming feed packets */
882
        break;
883

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

    
943
static int extract_rates(char *rates, int ratelen, const char *request)
944
{
945
    const char *p;
946

    
947
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
948
        if (strncasecmp(p, "Pragma:", 7) == 0) {
949
            const char *q = p + 7;
950

    
951
            while (*q && *q != '\n' && isspace(*q))
952
                q++;
953

    
954
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
955
                int stream_no;
956
                int rate_no;
957

    
958
                q += 20;
959

    
960
                memset(rates, 0xff, ratelen);
961

    
962
                while (1) {
963
                    while (*q && *q != '\n' && *q != ':')
964
                        q++;
965

    
966
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
967
                        break;
968
                    }
969
                    stream_no--;
970
                    if (stream_no < ratelen && stream_no >= 0) {
971
                        rates[stream_no] = rate_no;
972
                    }
973

    
974
                    while (*q && *q != '\n' && !isspace(*q))
975
                        q++;
976
                }
977

    
978
                return 1;
979
            }
980
        }
981
        p = strchr(p, '\n');
982
        if (!p)
983
            break;
984

    
985
        p++;
986
    }
987

    
988
    return 0;
989
}
990

    
991
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
992
{
993
    int i;
994
    int best_bitrate = 100000000;
995
    int best = -1;
996

    
997
    for (i = 0; i < feed->nb_streams; i++) {
998
        AVCodecContext *feed_codec = feed->streams[i]->codec;
999

    
1000
        if (feed_codec->codec_id != codec->codec_id ||
1001
            feed_codec->sample_rate != codec->sample_rate ||
1002
            feed_codec->width != codec->width ||
1003
            feed_codec->height != codec->height) {
1004
            continue;
1005
        }
1006

    
1007
        /* Potential stream */
1008

    
1009
        /* We want the fastest stream less than bit_rate, or the slowest
1010
         * faster than bit_rate
1011
         */
1012

    
1013
        if (feed_codec->bit_rate <= bit_rate) {
1014
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1015
                best_bitrate = feed_codec->bit_rate;
1016
                best = i;
1017
            }
1018
        } else {
1019
            if (feed_codec->bit_rate < best_bitrate) {
1020
                best_bitrate = feed_codec->bit_rate;
1021
                best = i;
1022
            }
1023
        }
1024
    }
1025

    
1026
    return best;
1027
}
1028

    
1029
static int modify_current_stream(HTTPContext *c, char *rates)
1030
{
1031
    int i;
1032
    FFStream *req = c->stream;
1033
    int action_required = 0;
1034

    
1035
    /* Not much we can do for a feed */
1036
    if (!req->feed)
1037
        return 0;
1038

    
1039
    for (i = 0; i < req->nb_streams; i++) {
1040
        AVCodecContext *codec = req->streams[i]->codec;
1041

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

    
1060
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1061
            action_required = 1;
1062
    }
1063

    
1064
    return action_required;
1065
}
1066

    
1067

    
1068
static void do_switch_stream(HTTPContext *c, int i)
1069
{
1070
    if (c->switch_feed_streams[i] >= 0) {
1071
#ifdef PHILIP
1072
        c->feed_streams[i] = c->switch_feed_streams[i];
1073
#endif
1074

    
1075
        /* Now update the stream */
1076
    }
1077
    c->switch_feed_streams[i] = -1;
1078
}
1079

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

    
1091
static void get_word(char *buf, int buf_size, const char **pp)
1092
{
1093
    const char *p;
1094
    char *q;
1095

    
1096
    p = *pp;
1097
    skip_spaces(&p);
1098
    q = buf;
1099
    while (!isspace(*p) && *p != '\0') {
1100
        if ((q - buf) < buf_size - 1)
1101
            *q++ = *p;
1102
        p++;
1103
    }
1104
    if (buf_size > 0)
1105
        *q = '\0';
1106
    *pp = p;
1107
}
1108

    
1109
static int validate_acl(FFStream *stream, HTTPContext *c)
1110
{
1111
    enum IPAddressAction last_action = IP_DENY;
1112
    IPAddressACL *acl;
1113
    struct in_addr *src = &c->from_addr.sin_addr;
1114
    unsigned long src_addr = ntohl(src->s_addr);
1115

    
1116
    for (acl = stream->acl; acl; acl = acl->next) {
1117
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1118
            return (acl->action == IP_ALLOW) ? 1 : 0;
1119
        }
1120
        last_action = acl->action;
1121
    }
1122

    
1123
    /* Nothing matched, so return not the last action */
1124
    return (last_action == IP_DENY) ? 1 : 0;
1125
}
1126

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

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

    
1153
enum RedirType {
1154
    REDIR_NONE,
1155
    REDIR_ASX,
1156
    REDIR_RAM,
1157
    REDIR_ASF,
1158
    REDIR_RTSP,
1159
    REDIR_SDP,
1160
};
1161

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

    
1178
    p = c->buffer;
1179
    get_word(cmd, sizeof(cmd), (const char **)&p);
1180
    pstrcpy(c->method, sizeof(c->method), cmd);
1181

    
1182
    if (!strcmp(cmd, "GET"))
1183
        c->post = 0;
1184
    else if (!strcmp(cmd, "POST"))
1185
        c->post = 1;
1186
    else
1187
        return -1;
1188

    
1189
    get_word(url, sizeof(url), (const char **)&p);
1190
    pstrcpy(c->url, sizeof(c->url), url);
1191

    
1192
    get_word(protocol, sizeof(protocol), (const char **)&p);
1193
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1194
        return -1;
1195

    
1196
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1197

    
1198
    if (ffserver_debug)
1199
        http_log("New connection: %s %s\n", cmd, url);
1200

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

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

    
1225
        p++;
1226
    }
1227

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

    
1247
    stream = first_stream;
1248
    while (stream != NULL) {
1249
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1250
            break;
1251
        stream = stream->next;
1252
    }
1253
    if (stream == NULL) {
1254
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1255
        goto send_error;
1256
    }
1257

    
1258
    c->stream = stream;
1259
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1260
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1261

    
1262
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1263
        c->http_error = 301;
1264
        q = c->buffer;
1265
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1266
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1267
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1268
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1269
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1270
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1271
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1272

    
1273
        /* prepare output buffer */
1274
        c->buffer_ptr = c->buffer;
1275
        c->buffer_end = q;
1276
        c->state = HTTPSTATE_SEND_HEADER;
1277
        return 0;
1278
    }
1279

    
1280
    /* If this is WMP, get the rate information */
1281
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1282
        if (modify_current_stream(c, ratebuf)) {
1283
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1284
                if (c->switch_feed_streams[i] >= 0)
1285
                    do_switch_stream(c, i);
1286
            }
1287
        }
1288
    }
1289

    
1290
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1291
        current_bandwidth += stream->bandwidth;
1292
    }
1293

    
1294
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1295
        c->http_error = 200;
1296
        q = c->buffer;
1297
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1298
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1299
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1300
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1301
        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");
1302
        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",
1303
            current_bandwidth, max_bandwidth);
1304
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1305

    
1306
        /* prepare output buffer */
1307
        c->buffer_ptr = c->buffer;
1308
        c->buffer_end = q;
1309
        c->state = HTTPSTATE_SEND_HEADER;
1310
        return 0;
1311
    }
1312

    
1313
    if (redir_type != REDIR_NONE) {
1314
        char *hostinfo = 0;
1315

    
1316
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1317
            if (strncasecmp(p, "Host:", 5) == 0) {
1318
                hostinfo = p + 5;
1319
                break;
1320
            }
1321
            p = strchr(p, '\n');
1322
            if (!p)
1323
                break;
1324

    
1325
            p++;
1326
        }
1327

    
1328
        if (hostinfo) {
1329
            char *eoh;
1330
            char hostbuf[260];
1331

    
1332
            while (isspace(*hostinfo))
1333
                hostinfo++;
1334

    
1335
            eoh = strchr(hostinfo, '\n');
1336
            if (eoh) {
1337
                if (eoh[-1] == '\r')
1338
                    eoh--;
1339

    
1340
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1341
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1342
                    hostbuf[eoh - hostinfo] = 0;
1343

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

    
1396
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1397
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1398
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1399

    
1400
                            len = sizeof(my_addr);
1401
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1402

    
1403
                            /* XXX: should use a dynamic buffer */
1404
                            sdp_data_size = prepare_sdp_description(stream,
1405
                                                                    &sdp_data,
1406
                                                                    my_addr.sin_addr);
1407
                            if (sdp_data_size > 0) {
1408
                                memcpy(q, sdp_data, sdp_data_size);
1409
                                q += sdp_data_size;
1410
                                *q = '\0';
1411
                                av_free(sdp_data);
1412
                            }
1413
                        }
1414
                        break;
1415
                    default:
1416
                        av_abort();
1417
                        break;
1418
                    }
1419

    
1420
                    /* prepare output buffer */
1421
                    c->buffer_ptr = c->buffer;
1422
                    c->buffer_end = q;
1423
                    c->state = HTTPSTATE_SEND_HEADER;
1424
                    return 0;
1425
                }
1426
            }
1427
        }
1428

    
1429
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1430
        goto send_error;
1431
    }
1432

    
1433
    stream->conns_served++;
1434

    
1435
    /* XXX: add there authenticate and IP match */
1436

    
1437
    if (c->post) {
1438
        /* if post, it means a feed is being sent */
1439
        if (!stream->is_feed) {
1440
            /* However it might be a status report from WMP! Lets log the data
1441
             * as it might come in handy one day
1442
             */
1443
            char *logline = 0;
1444
            int client_id = 0;
1445

    
1446
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1447
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1448
                    logline = p;
1449
                    break;
1450
                }
1451
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1452
                    client_id = strtol(p + 18, 0, 10);
1453
                }
1454
                p = strchr(p, '\n');
1455
                if (!p)
1456
                    break;
1457

    
1458
                p++;
1459
            }
1460

    
1461
            if (logline) {
1462
                char *eol = strchr(logline, '\n');
1463

    
1464
                logline += 17;
1465

    
1466
                if (eol) {
1467
                    if (eol[-1] == '\r')
1468
                        eol--;
1469
                    http_log("%.*s\n", (int) (eol - logline), logline);
1470
                    c->suppress_log = 1;
1471
                }
1472
            }
1473

    
1474
#ifdef DEBUG_WMP
1475
            http_log("\nGot request:\n%s\n", c->buffer);
1476
#endif
1477

    
1478
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1479
                HTTPContext *wmpc;
1480

    
1481
                /* Now we have to find the client_id */
1482
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1483
                    if (wmpc->wmp_client_id == client_id)
1484
                        break;
1485
                }
1486

    
1487
                if (wmpc) {
1488
                    if (modify_current_stream(wmpc, ratebuf)) {
1489
                        wmpc->switch_pending = 1;
1490
                    }
1491
                }
1492
            }
1493

    
1494
            snprintf(msg, sizeof(msg), "POST command not handled");
1495
            c->stream = 0;
1496
            goto send_error;
1497
        }
1498
        if (http_start_receive_data(c) < 0) {
1499
            snprintf(msg, sizeof(msg), "could not open feed");
1500
            goto send_error;
1501
        }
1502
        c->http_error = 0;
1503
        c->state = HTTPSTATE_RECEIVE_DATA;
1504
        return 0;
1505
    }
1506

    
1507
#ifdef DEBUG_WMP
1508
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1509
        http_log("\nGot request:\n%s\n", c->buffer);
1510
    }
1511
#endif
1512

    
1513
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1514
        goto send_stats;
1515

    
1516
    /* open input stream */
1517
    if (open_input_stream(c, info) < 0) {
1518
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1519
        goto send_error;
1520
    }
1521

    
1522
    /* prepare http header */
1523
    q = c->buffer;
1524
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1525
    mime_type = c->stream->fmt->mime_type;
1526
    if (!mime_type)
1527
        mime_type = "application/x-octet_stream";
1528
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1529

    
1530
    /* for asf, we need extra headers */
1531
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1532
        /* Need to allocate a client id */
1533

    
1534
        c->wmp_client_id = random() & 0x7fffffff;
1535

    
1536
        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);
1537
    }
1538
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1539
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1540

    
1541
    /* prepare output buffer */
1542
    c->http_error = 0;
1543
    c->buffer_ptr = c->buffer;
1544
    c->buffer_end = q;
1545
    c->state = HTTPSTATE_SEND_HEADER;
1546
    return 0;
1547
 send_error:
1548
    c->http_error = 404;
1549
    q = c->buffer;
1550
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1551
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1552
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1553
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1554
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1555
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1556
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
1557

    
1558
    /* prepare output buffer */
1559
    c->buffer_ptr = c->buffer;
1560
    c->buffer_end = q;
1561
    c->state = HTTPSTATE_SEND_HEADER;
1562
    return 0;
1563
 send_stats:
1564
    compute_stats(c);
1565
    c->http_error = 200; /* horrible : we use this value to avoid
1566
                            going to the send data state */
1567
    c->state = HTTPSTATE_SEND_HEADER;
1568
    return 0;
1569
}
1570

    
1571
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1572
{
1573
    static const char *suffix = " kMGTP";
1574
    const char *s;
1575

    
1576
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1577
    }
1578

    
1579
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1580
}
1581

    
1582
static void compute_stats(HTTPContext *c)
1583
{
1584
    HTTPContext *c1;
1585
    FFStream *stream;
1586
    char *p;
1587
    time_t ti;
1588
    int i, len;
1589
    ByteIOContext pb1, *pb = &pb1;
1590

    
1591
    if (url_open_dyn_buf(pb) < 0) {
1592
        /* XXX: return an error ? */
1593
        c->buffer_ptr = c->buffer;
1594
        c->buffer_end = c->buffer;
1595
        return;
1596
    }
1597

    
1598
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1599
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1600
    url_fprintf(pb, "Pragma: no-cache\r\n");
1601
    url_fprintf(pb, "\r\n");
1602

    
1603
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1604
    if (c->stream->feed_filename) {
1605
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1606
    }
1607
    url_fprintf(pb, "</HEAD>\n<BODY>");
1608
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1609
    /* format status */
1610
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1611
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1612
    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");
1613
    stream = first_stream;
1614
    while (stream != NULL) {
1615
        char sfilename[1024];
1616
        char *eosf;
1617

    
1618
        if (stream->feed != stream) {
1619
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1620
            eosf = sfilename + strlen(sfilename);
1621
            if (eosf - sfilename >= 4) {
1622
                if (strcmp(eosf - 4, ".asf") == 0) {
1623
                    strcpy(eosf - 4, ".asx");
1624
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1625
                    strcpy(eosf - 3, ".ram");
1626
                } else if (stream->fmt == &rtp_mux) {
1627
                    /* generate a sample RTSP director if
1628
                       unicast. Generate an SDP redirector if
1629
                       multicast */
1630
                    eosf = strrchr(sfilename, '.');
1631
                    if (!eosf)
1632
                        eosf = sfilename + strlen(sfilename);
1633
                    if (stream->is_multicast)
1634
                        strcpy(eosf, ".sdp");
1635
                    else
1636
                        strcpy(eosf, ".rtsp");
1637
                }
1638
            }
1639

    
1640
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1641
                         sfilename, stream->filename);
1642
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1643
                        stream->conns_served);
1644
            fmt_bytecount(pb, stream->bytes_served);
1645
            switch(stream->stream_type) {
1646
            case STREAM_TYPE_LIVE:
1647
                {
1648
                    int audio_bit_rate = 0;
1649
                    int video_bit_rate = 0;
1650
                    const char *audio_codec_name = "";
1651
                    const char *video_codec_name = "";
1652
                    const char *audio_codec_name_extra = "";
1653
                    const char *video_codec_name_extra = "";
1654

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

    
1704
    stream = first_stream;
1705
    while (stream != NULL) {
1706
        if (stream->feed == stream) {
1707
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1708
            if (stream->pid) {
1709
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1710

    
1711
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1712
                {
1713
                    FILE *pid_stat;
1714
                    char ps_cmd[64];
1715

    
1716
                    /* This is somewhat linux specific I guess */
1717
                    snprintf(ps_cmd, sizeof(ps_cmd),
1718
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1719
                             stream->pid);
1720

    
1721
                    pid_stat = popen(ps_cmd, "r");
1722
                    if (pid_stat) {
1723
                        char cpuperc[10];
1724
                        char cpuused[64];
1725

    
1726
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1727
                                   cpuused) == 2) {
1728
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1729
                                         cpuperc, cpuused);
1730
                        }
1731
                        fclose(pid_stat);
1732
                    }
1733
                }
1734
#endif
1735

    
1736
                url_fprintf(pb, "<p>");
1737
            }
1738
            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");
1739

    
1740
            for (i = 0; i < stream->nb_streams; i++) {
1741
                AVStream *st = stream->streams[i];
1742
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1743
                const char *type = "unknown";
1744
                char parameters[64];
1745

    
1746
                parameters[0] = 0;
1747

    
1748
                switch(st->codec->codec_type) {
1749
                case CODEC_TYPE_AUDIO:
1750
                    type = "audio";
1751
                    break;
1752
                case CODEC_TYPE_VIDEO:
1753
                    type = "video";
1754
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1755
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1756
                    break;
1757
                default:
1758
                    av_abort();
1759
                }
1760
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1761
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1762
            }
1763
            url_fprintf(pb, "</table>\n");
1764

    
1765
        }
1766
        stream = stream->next;
1767
    }
1768

    
1769
#if 0
1770
    {
1771
        float avg;
1772
        AVCodecContext *enc;
1773
        char buf[1024];
1774

1775
        /* feed status */
1776
        stream = first_feed;
1777
        while (stream != NULL) {
1778
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1779
            url_fprintf(pb, "<TABLE>\n");
1780
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1781
            for(i=0;i<stream->nb_streams;i++) {
1782
                AVStream *st = stream->streams[i];
1783
                FeedData *fdata = st->priv_data;
1784
                enc = st->codec;
1785

1786
                avcodec_string(buf, sizeof(buf), enc);
1787
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1788
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1789
                    avg /= enc->frame_size;
1790
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
1791
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1792
            }
1793
            url_fprintf(pb, "</TABLE>\n");
1794
            stream = stream->next_feed;
1795
        }
1796
    }
1797
#endif
1798

    
1799
    /* connection status */
1800
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1801

    
1802
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1803
                 nb_connections, nb_max_connections);
1804

    
1805
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1806
                 current_bandwidth, max_bandwidth);
1807

    
1808
    url_fprintf(pb, "<TABLE>\n");
1809
    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");
1810
    c1 = first_http_ctx;
1811
    i = 0;
1812
    while (c1 != NULL) {
1813
        int bitrate;
1814
        int j;
1815

    
1816
        bitrate = 0;
1817
        if (c1->stream) {
1818
            for (j = 0; j < c1->stream->nb_streams; j++) {
1819
                if (!c1->stream->feed) {
1820
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1821
                } else {
1822
                    if (c1->feed_streams[j] >= 0) {
1823
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1824
                    }
1825
                }
1826
            }
1827
        }
1828

    
1829
        i++;
1830
        p = inet_ntoa(c1->from_addr.sin_addr);
1831
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1832
                    i,
1833
                    c1->stream ? c1->stream->filename : "",
1834
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1835
                    p,
1836
                    c1->protocol,
1837
                    http_state[c1->state]);
1838
        fmt_bytecount(pb, bitrate);
1839
        url_fprintf(pb, "<td align=right>");
1840
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1841
        url_fprintf(pb, "<td align=right>");
1842
        fmt_bytecount(pb, c1->data_count);
1843
        url_fprintf(pb, "\n");
1844
        c1 = c1->next;
1845
    }
1846
    url_fprintf(pb, "</TABLE>\n");
1847

    
1848
    /* date */
1849
    ti = time(NULL);
1850
    p = ctime(&ti);
1851
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1852
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1853

    
1854
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1855
    c->buffer_ptr = c->pb_buffer;
1856
    c->buffer_end = c->pb_buffer + len;
1857
}
1858

    
1859
/* check if the parser needs to be opened for stream i */
1860
static void open_parser(AVFormatContext *s, int i)
1861
{
1862
    AVStream *st = s->streams[i];
1863
    AVCodec *codec;
1864

    
1865
    if (!st->codec->codec) {
1866
        codec = avcodec_find_decoder(st->codec->codec_id);
1867
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1868
            st->codec->parse_only = 1;
1869
            if (avcodec_open(st->codec, codec) < 0) {
1870
                st->codec->parse_only = 0;
1871
            }
1872
        }
1873
    }
1874
}
1875

    
1876
static int open_input_stream(HTTPContext *c, const char *info)
1877
{
1878
    char buf[128];
1879
    char input_filename[1024];
1880
    AVFormatContext *s;
1881
    int buf_size, i;
1882
    int64_t stream_pos;
1883

    
1884
    /* find file name */
1885
    if (c->stream->feed) {
1886
        strcpy(input_filename, c->stream->feed->feed_filename);
1887
        buf_size = FFM_PACKET_SIZE;
1888
        /* compute position (absolute time) */
1889
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1890
            stream_pos = parse_date(buf, 0);
1891
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1892
            int prebuffer = strtol(buf, 0, 10);
1893
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1894
        } else {
1895
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1896
        }
1897
    } else {
1898
        strcpy(input_filename, c->stream->feed_filename);
1899
        buf_size = 0;
1900
        /* compute position (relative time) */
1901
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1902
            stream_pos = parse_date(buf, 1);
1903
        } else {
1904
            stream_pos = 0;
1905
        }
1906
    }
1907
    if (input_filename[0] == '\0')
1908
        return -1;
1909

    
1910
#if 0
1911
    { time_t when = stream_pos / 1000000;
1912
    http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1913
    }
1914
#endif
1915

    
1916
    /* open stream */
1917
    if (av_open_input_file(&s, input_filename, c->stream->ifmt,
1918
                           buf_size, c->stream->ap_in) < 0) {
1919
        http_log("%s not found", input_filename);
1920
        return -1;
1921
    }
1922
    c->fmt_in = s;
1923

    
1924
    /* open each parser */
1925
    for(i=0;i<s->nb_streams;i++)
1926
        open_parser(s, i);
1927

    
1928
    /* choose stream as clock source (we favorize video stream if
1929
       present) for packet sending */
1930
    c->pts_stream_index = 0;
1931
    for(i=0;i<c->stream->nb_streams;i++) {
1932
        if (c->pts_stream_index == 0 &&
1933
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1934
            c->pts_stream_index = i;
1935
        }
1936
    }
1937

    
1938
#if 1
1939
    if (c->fmt_in->iformat->read_seek) {
1940
        c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
1941
    }
1942
#endif
1943
    /* set the start time (needed for maxtime and RTP packet timing) */
1944
    c->start_time = cur_time;
1945
    c->first_pts = AV_NOPTS_VALUE;
1946
    return 0;
1947
}
1948

    
1949
/* return the server clock (in us) */
1950
static int64_t get_server_clock(HTTPContext *c)
1951
{
1952
    /* compute current pts value from system time */
1953
    return (int64_t)(cur_time - c->start_time) * 1000LL;
1954
}
1955

    
1956
/* return the estimated time at which the current packet must be sent
1957
   (in us) */
1958
static int64_t get_packet_send_clock(HTTPContext *c)
1959
{
1960
    int bytes_left, bytes_sent, frame_bytes;
1961

    
1962
    frame_bytes = c->cur_frame_bytes;
1963
    if (frame_bytes <= 0) {
1964
        return c->cur_pts;
1965
    } else {
1966
        bytes_left = c->buffer_end - c->buffer_ptr;
1967
        bytes_sent = frame_bytes - bytes_left;
1968
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1969
    }
1970
}
1971

    
1972

    
1973
static int http_prepare_data(HTTPContext *c)
1974
{
1975
    int i, len, ret;
1976
    AVFormatContext *ctx;
1977

    
1978
    av_freep(&c->pb_buffer);
1979
    switch(c->state) {
1980
    case HTTPSTATE_SEND_DATA_HEADER:
1981
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1982
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author),
1983
                c->stream->author);
1984
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment),
1985
                c->stream->comment);
1986
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright),
1987
                c->stream->copyright);
1988
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title),
1989
                c->stream->title);
1990

    
1991
        /* open output stream by using specified codecs */
1992
        c->fmt_ctx.oformat = c->stream->fmt;
1993
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
1994
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1995
            AVStream *st;
1996
            AVStream *src;
1997
            st = av_mallocz(sizeof(AVStream));
1998
            st->codec= avcodec_alloc_context();
1999
            c->fmt_ctx.streams[i] = st;
2000
            /* if file or feed, then just take streams from FFStream struct */
2001
            if (!c->stream->feed ||
2002
                c->stream->feed == c->stream)
2003
                src = c->stream->streams[i];
2004
            else
2005
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2006

    
2007
            *st = *src;
2008
            st->priv_data = 0;
2009
            st->codec->frame_number = 0; /* XXX: should be done in
2010
                                           AVStream, not in codec */
2011
            /* I'm pretty sure that this is not correct...
2012
             * However, without it, we crash
2013
             */
2014
            st->codec->coded_frame = &dummy_frame;
2015
        }
2016
        c->got_key_frame = 0;
2017

    
2018
        /* prepare header and save header data in a stream */
2019
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2020
            /* XXX: potential leak */
2021
            return -1;
2022
        }
2023
        c->fmt_ctx.pb.is_streamed = 1;
2024

    
2025
        av_set_parameters(&c->fmt_ctx, NULL);
2026
        av_write_header(&c->fmt_ctx);
2027

    
2028
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2029
        c->buffer_ptr = c->pb_buffer;
2030
        c->buffer_end = c->pb_buffer + len;
2031

    
2032
        c->state = HTTPSTATE_SEND_DATA;
2033
        c->last_packet_sent = 0;
2034
        break;
2035
    case HTTPSTATE_SEND_DATA:
2036
        /* find a new packet */
2037
        {
2038
            AVPacket pkt;
2039

    
2040
            /* read a packet from the input stream */
2041
            if (c->stream->feed) {
2042
                ffm_set_write_index(c->fmt_in,
2043
                                    c->stream->feed->feed_write_index,
2044
                                    c->stream->feed->feed_size);
2045
            }
2046

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

    
2116
                    send_it:
2117
                        /* specific handling for RTP: we use several
2118
                           output stream (one for each RTP
2119
                           connection). XXX: need more abstract handling */
2120
                        if (c->is_packetized) {
2121
                            AVStream *st;
2122
                            /* compute send time and duration */
2123
                            st = c->fmt_in->streams[pkt.stream_index];
2124
                            c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2125
                            if (st->start_time != AV_NOPTS_VALUE)
2126
                                c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2127
                            c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2128
#if 0
2129
                            printf("index=%d pts=%0.3f duration=%0.6f\n",
2130
                                   pkt.stream_index,
2131
                                   (double)c->cur_pts /
2132
                                   AV_TIME_BASE,
2133
                                   (double)c->cur_frame_duration /
2134
                                   AV_TIME_BASE);
2135
#endif
2136
                            /* find RTP context */
2137
                            c->packet_stream_index = pkt.stream_index;
2138
                            ctx = c->rtp_ctx[c->packet_stream_index];
2139
                            if(!ctx) {
2140
                              av_free_packet(&pkt);
2141
                              break;
2142
                            }
2143
                            codec = ctx->streams[0]->codec;
2144
                            /* only one stream per RTP connection */
2145
                            pkt.stream_index = 0;
2146
                        } else {
2147
                            ctx = &c->fmt_ctx;
2148
                            /* Fudge here */
2149
                            codec = ctx->streams[pkt.stream_index]->codec;
2150
                        }
2151

    
2152
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2153
                        if (c->is_packetized) {
2154
                            int max_packet_size;
2155
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2156
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2157
                            else
2158
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2159
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2160
                        } else {
2161
                            ret = url_open_dyn_buf(&ctx->pb);
2162
                        }
2163
                        if (ret < 0) {
2164
                            /* XXX: potential leak */
2165
                            return -1;
2166
                        }
2167
                        if (av_write_frame(ctx, &pkt)) {
2168
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2169
                        }
2170

    
2171
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2172
                        c->cur_frame_bytes = len;
2173
                        c->buffer_ptr = c->pb_buffer;
2174
                        c->buffer_end = c->pb_buffer + len;
2175

    
2176
                        codec->frame_number++;
2177
                        if (len == 0)
2178
                            goto redo;
2179
                    }
2180
                    av_free_packet(&pkt);
2181
                }
2182
            }
2183
        }
2184
        break;
2185
    default:
2186
    case HTTPSTATE_SEND_DATA_TRAILER:
2187
        /* last packet test ? */
2188
        if (c->last_packet_sent || c->is_packetized)
2189
            return -1;
2190
        ctx = &c->fmt_ctx;
2191
        /* prepare header */
2192
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2193
            /* XXX: potential leak */
2194
            return -1;
2195
        }
2196
        av_write_trailer(ctx);
2197
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2198
        c->buffer_ptr = c->pb_buffer;
2199
        c->buffer_end = c->pb_buffer + len;
2200

    
2201
        c->last_packet_sent = 1;
2202
        break;
2203
    }
2204
    return 0;
2205
}
2206

    
2207
/* in bit/s */
2208
#define SHORT_TERM_BANDWIDTH 8000000
2209

    
2210
/* should convert the format at the same time */
2211
/* send data starting at c->buffer_ptr to the output connection
2212
   (either UDP or TCP connection) */
2213
static int http_send_data(HTTPContext *c)
2214
{
2215
    int len, ret;
2216

    
2217
    for(;;) {
2218
        if (c->buffer_ptr >= c->buffer_end) {
2219
            ret = http_prepare_data(c);
2220
            if (ret < 0)
2221
                return -1;
2222
            else if (ret != 0) {
2223
                /* state change requested */
2224
                break;
2225
            }
2226
        } else {
2227
            if (c->is_packetized) {
2228
                /* RTP data output */
2229
                len = c->buffer_end - c->buffer_ptr;
2230
                if (len < 4) {
2231
                    /* fail safe - should never happen */
2232
                fail1:
2233
                    c->buffer_ptr = c->buffer_end;
2234
                    return 0;
2235
                }
2236
                len = (c->buffer_ptr[0] << 24) |
2237
                    (c->buffer_ptr[1] << 16) |
2238
                    (c->buffer_ptr[2] << 8) |
2239
                    (c->buffer_ptr[3]);
2240
                if (len > (c->buffer_end - c->buffer_ptr))
2241
                    goto fail1;
2242
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2243
                    /* nothing to send yet: we can wait */
2244
                    return 0;
2245
                }
2246

    
2247
                c->data_count += len;
2248
                update_datarate(&c->datarate, c->data_count);
2249
                if (c->stream)
2250
                    c->stream->bytes_served += len;
2251

    
2252
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2253
                    /* RTP packets are sent inside the RTSP TCP connection */
2254
                    ByteIOContext pb1, *pb = &pb1;
2255
                    int interleaved_index, size;
2256
                    uint8_t header[4];
2257
                    HTTPContext *rtsp_c;
2258

    
2259
                    rtsp_c = c->rtsp_c;
2260
                    /* if no RTSP connection left, error */
2261
                    if (!rtsp_c)
2262
                        return -1;
2263
                    /* if already sending something, then wait. */
2264
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2265
                        break;
2266
                    }
2267
                    if (url_open_dyn_buf(pb) < 0)
2268
                        goto fail1;
2269
                    interleaved_index = c->packet_stream_index * 2;
2270
                    /* RTCP packets are sent at odd indexes */
2271
                    if (c->buffer_ptr[1] == 200)
2272
                        interleaved_index++;
2273
                    /* write RTSP TCP header */
2274
                    header[0] = '$';
2275
                    header[1] = interleaved_index;
2276
                    header[2] = len >> 8;
2277
                    header[3] = len;
2278
                    put_buffer(pb, header, 4);
2279
                    /* write RTP packet data */
2280
                    c->buffer_ptr += 4;
2281
                    put_buffer(pb, c->buffer_ptr, len);
2282
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2283
                    /* prepare asynchronous TCP sending */
2284
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2285
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2286
                    c->buffer_ptr += len;
2287

    
2288
                    /* send everything we can NOW */
2289
                    len = write(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2290
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr);
2291
                    if (len > 0) {
2292
                        rtsp_c->packet_buffer_ptr += len;
2293
                    }
2294
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2295
                        /* if we could not send all the data, we will
2296
                           send it later, so a new state is needed to
2297
                           "lock" the RTSP TCP connection */
2298
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2299
                        break;
2300
                    } else {
2301
                        /* all data has been sent */
2302
                        av_freep(&c->packet_buffer);
2303
                    }
2304
                } else {
2305
                    /* send RTP packet directly in UDP */
2306
                    c->buffer_ptr += 4;
2307
                    url_write(c->rtp_handles[c->packet_stream_index],
2308
                              c->buffer_ptr, len);
2309
                    c->buffer_ptr += len;
2310
                    /* here we continue as we can send several packets per 10 ms slot */
2311
                }
2312
            } else {
2313
                /* TCP data output */
2314
                len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2315
                if (len < 0) {
2316
                    if (errno != EAGAIN && errno != EINTR) {
2317
                        /* error : close connection */
2318
                        return -1;
2319
                    } else {
2320
                        return 0;
2321
                    }
2322
                } else {
2323
                    c->buffer_ptr += len;
2324
                }
2325
                c->data_count += len;
2326
                update_datarate(&c->datarate, c->data_count);
2327
                if (c->stream)
2328
                    c->stream->bytes_served += len;
2329
                break;
2330
            }
2331
        }
2332
    } /* for(;;) */
2333
    return 0;
2334
}
2335

    
2336
static int http_start_receive_data(HTTPContext *c)
2337
{
2338
    int fd;
2339

    
2340
    if (c->stream->feed_opened)
2341
        return -1;
2342

    
2343
    /* Don't permit writing to this one */
2344
    if (c->stream->readonly)
2345
        return -1;
2346

    
2347
    /* open feed */
2348
    fd = open(c->stream->feed_filename, O_RDWR);
2349
    if (fd < 0)
2350
        return -1;
2351
    c->feed_fd = fd;
2352

    
2353
    c->stream->feed_write_index = ffm_read_write_index(fd);
2354
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2355
    lseek(fd, 0, SEEK_SET);
2356

    
2357
    /* init buffer input */
2358
    c->buffer_ptr = c->buffer;
2359
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2360
    c->stream->feed_opened = 1;
2361
    return 0;
2362
}
2363

    
2364
static int http_receive_data(HTTPContext *c)
2365
{
2366
    HTTPContext *c1;
2367

    
2368
    if (c->buffer_end > c->buffer_ptr) {
2369
        int len;
2370

    
2371
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2372
        if (len < 0) {
2373
            if (errno != EAGAIN && errno != EINTR) {
2374
                /* error : close connection */
2375
                goto fail;
2376
            }
2377
        } else if (len == 0) {
2378
            /* end of connection : close it */
2379
            goto fail;
2380
        } else {
2381
            c->buffer_ptr += len;
2382
            c->data_count += len;
2383
            update_datarate(&c->datarate, c->data_count);
2384
        }
2385
    }
2386

    
2387
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2388
        if (c->buffer[0] != 'f' ||
2389
            c->buffer[1] != 'm') {
2390
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2391
            goto fail;
2392
        }
2393
    }
2394

    
2395
    if (c->buffer_ptr >= c->buffer_end) {
2396
        FFStream *feed = c->stream;
2397
        /* a packet has been received : write it in the store, except
2398
           if header */
2399
        if (c->data_count > FFM_PACKET_SIZE) {
2400

    
2401
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2402
            /* XXX: use llseek or url_seek */
2403
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2404
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2405

    
2406
            feed->feed_write_index += FFM_PACKET_SIZE;
2407
            /* update file size */
2408
            if (feed->feed_write_index > c->stream->feed_size)
2409
                feed->feed_size = feed->feed_write_index;
2410

    
2411
            /* handle wrap around if max file size reached */
2412
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2413
                feed->feed_write_index = FFM_PACKET_SIZE;
2414

    
2415
            /* write index */
2416
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2417

    
2418
            /* wake up any waiting connections */
2419
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2420
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2421
                    c1->stream->feed == c->stream->feed) {
2422
                    c1->state = HTTPSTATE_SEND_DATA;
2423
                }
2424
            }
2425
        } else {
2426
            /* We have a header in our hands that contains useful data */
2427
            AVFormatContext s;
2428
            AVInputFormat *fmt_in;
2429
            ByteIOContext *pb = &s.pb;
2430
            int i;
2431

    
2432
            memset(&s, 0, sizeof(s));
2433

    
2434
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2435
            pb->buf_end = c->buffer_end;        /* ?? */
2436
            pb->is_streamed = 1;
2437

    
2438
            /* use feed output format name to find corresponding input format */
2439
            fmt_in = av_find_input_format(feed->fmt->name);
2440
            if (!fmt_in)
2441
                goto fail;
2442

    
2443
            if (fmt_in->priv_data_size > 0) {
2444
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2445
                if (!s.priv_data)
2446
                    goto fail;
2447
            } else
2448
                s.priv_data = NULL;
2449

    
2450
            if (fmt_in->read_header(&s, 0) < 0) {
2451
                av_freep(&s.priv_data);
2452
                goto fail;
2453
            }
2454

    
2455
            /* Now we have the actual streams */
2456
            if (s.nb_streams != feed->nb_streams) {
2457
                av_freep(&s.priv_data);
2458
                goto fail;
2459
            }
2460
            for (i = 0; i < s.nb_streams; i++) {
2461
                memcpy(feed->streams[i]->codec,
2462
                       s.streams[i]->codec, sizeof(AVCodecContext));
2463
            }
2464
            av_freep(&s.priv_data);
2465
        }
2466
        c->buffer_ptr = c->buffer;
2467
    }
2468

    
2469
    return 0;
2470
 fail:
2471
    c->stream->feed_opened = 0;
2472
    close(c->feed_fd);
2473
    return -1;
2474
}
2475

    
2476
/********************************************************************/
2477
/* RTSP handling */
2478

    
2479
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2480
{
2481
    const char *str;
2482
    time_t ti;
2483
    char *p;
2484
    char buf2[32];
2485

    
2486
    switch(error_number) {
2487
#define DEF(n, c, s) case c: str = s; break;
2488
#include "rtspcodes.h"
2489
#undef DEF
2490
    default:
2491
        str = "Unknown Error";
2492
        break;
2493
    }
2494

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

    
2498
    /* output GMT time */
2499
    ti = time(NULL);
2500
    p = ctime(&ti);
2501
    strcpy(buf2, p);
2502
    p = buf2 + strlen(p) - 1;
2503
    if (*p == '\n')
2504
        *p = '\0';
2505
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2506
}
2507

    
2508
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2509
{
2510
    rtsp_reply_header(c, error_number);
2511
    url_fprintf(c->pb, "\r\n");
2512
}
2513

    
2514
static int rtsp_parse_request(HTTPContext *c)
2515
{
2516
    const char *p, *p1, *p2;
2517
    char cmd[32];
2518
    char url[1024];
2519
    char protocol[32];
2520
    char line[1024];
2521
    ByteIOContext pb1;
2522
    int len;
2523
    RTSPHeader header1, *header = &header1;
2524

    
2525
    c->buffer_ptr[0] = '\0';
2526
    p = c->buffer;
2527

    
2528
    get_word(cmd, sizeof(cmd), &p);
2529
    get_word(url, sizeof(url), &p);
2530
    get_word(protocol, sizeof(protocol), &p);
2531

    
2532
    pstrcpy(c->method, sizeof(c->method), cmd);
2533
    pstrcpy(c->url, sizeof(c->url), url);
2534
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2535

    
2536
    c->pb = &pb1;
2537
    if (url_open_dyn_buf(c->pb) < 0) {
2538
        /* XXX: cannot do more */
2539
        c->pb = NULL; /* safety */
2540
        return -1;
2541
    }
2542

    
2543
    /* check version name */
2544
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2545
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2546
        goto the_end;
2547
    }
2548

    
2549
    /* parse each header line */
2550
    memset(header, 0, sizeof(RTSPHeader));
2551
    /* skip to next line */
2552
    while (*p != '\n' && *p != '\0')
2553
        p++;
2554
    if (*p == '\n')
2555
        p++;
2556
    while (*p != '\0') {
2557
        p1 = strchr(p, '\n');
2558
        if (!p1)
2559
            break;
2560
        p2 = p1;
2561
        if (p2 > p && p2[-1] == '\r')
2562
            p2--;
2563
        /* skip empty line */
2564
        if (p2 == p)
2565
            break;
2566
        len = p2 - p;
2567
        if (len > sizeof(line) - 1)
2568
            len = sizeof(line) - 1;
2569
        memcpy(line, p, len);
2570
        line[len] = '\0';
2571
        rtsp_parse_line(header, line);
2572
        p = p1 + 1;
2573
    }
2574

    
2575
    /* handle sequence number */
2576
    c->seq = header->seq;
2577

    
2578
    if (!strcmp(cmd, "DESCRIBE")) {
2579
        rtsp_cmd_describe(c, url);
2580
    } else if (!strcmp(cmd, "OPTIONS")) {
2581
        rtsp_cmd_options(c, url);
2582
    } else if (!strcmp(cmd, "SETUP")) {
2583
        rtsp_cmd_setup(c, url, header);
2584
    } else if (!strcmp(cmd, "PLAY")) {
2585
        rtsp_cmd_play(c, url, header);
2586
    } else if (!strcmp(cmd, "PAUSE")) {
2587
        rtsp_cmd_pause(c, url, header);
2588
    } else if (!strcmp(cmd, "TEARDOWN")) {
2589
        rtsp_cmd_teardown(c, url, header);
2590
    } else {
2591
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2592
    }
2593
 the_end:
2594
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2595
    c->pb = NULL; /* safety */
2596
    if (len < 0) {
2597
        /* XXX: cannot do more */
2598
        return -1;
2599
    }
2600
    c->buffer_ptr = c->pb_buffer;
2601
    c->buffer_end = c->pb_buffer + len;
2602
    c->state = RTSPSTATE_SEND_REPLY;
2603
    return 0;
2604
}
2605

    
2606
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2607
   AVFormatContext */
2608
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2609
                                   struct in_addr my_ip)
2610
{
2611
    ByteIOContext pb1, *pb = &pb1;
2612
    int i, payload_type, port, private_payload_type, j;
2613
    const char *ipstr, *title, *mediatype;
2614
    AVStream *st;
2615

    
2616
    if (url_open_dyn_buf(pb) < 0)
2617
        return -1;
2618

    
2619
    /* general media info */
2620

    
2621
    url_fprintf(pb, "v=0\n");
2622
    ipstr = inet_ntoa(my_ip);
2623
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2624
    title = stream->title;
2625
    if (title[0] == '\0')
2626
        title = "No Title";
2627
    url_fprintf(pb, "s=%s\n", title);
2628
    if (stream->comment[0] != '\0')
2629
        url_fprintf(pb, "i=%s\n", stream->comment);
2630
    if (stream->is_multicast) {
2631
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2632
    }
2633
    /* for each stream, we output the necessary info */
2634
    private_payload_type = RTP_PT_PRIVATE;
2635
    for(i = 0; i < stream->nb_streams; i++) {
2636
        st = stream->streams[i];
2637
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2638
            mediatype = "video";
2639
        } else {
2640
            switch(st->codec->codec_type) {
2641
            case CODEC_TYPE_AUDIO:
2642
                mediatype = "audio";
2643
                break;
2644
            case CODEC_TYPE_VIDEO:
2645
                mediatype = "video";
2646
                break;
2647
            default:
2648
                mediatype = "application";
2649
                break;
2650
            }
2651
        }
2652
        /* NOTE: the port indication is not correct in case of
2653
           unicast. It is not an issue because RTSP gives it */
2654
        payload_type = rtp_get_payload_type(st->codec);
2655
        if (payload_type < 0)
2656
            payload_type = private_payload_type++;
2657
        if (stream->is_multicast) {
2658
            port = stream->multicast_port + 2 * i;
2659
        } else {
2660
            port = 0;
2661
        }
2662
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2663
                    mediatype, port, payload_type);
2664
        if (payload_type >= RTP_PT_PRIVATE) {
2665
            /* for private payload type, we need to give more info */
2666
            switch(st->codec->codec_id) {
2667
            case CODEC_ID_MPEG4:
2668
                {
2669
                    uint8_t *data;
2670
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2671
                                payload_type, 90000);
2672
                    /* we must also add the mpeg4 header */
2673
                    data = st->codec->extradata;
2674
                    if (data) {
2675
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2676
                        for(j=0;j<st->codec->extradata_size;j++) {
2677
                            url_fprintf(pb, "%02x", data[j]);
2678
                        }
2679
                        url_fprintf(pb, "\n");
2680
                    }
2681
                }
2682
                break;
2683
            default:
2684
                /* XXX: add other codecs ? */
2685
                goto fail;
2686
            }
2687
        }
2688
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2689
    }
2690
    return url_close_dyn_buf(pb, pbuffer);
2691
 fail:
2692
    url_close_dyn_buf(pb, pbuffer);
2693
    av_free(*pbuffer);
2694
    return -1;
2695
}
2696

    
2697
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2698
{
2699
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2700
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2701
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2702
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2703
    url_fprintf(c->pb, "\r\n");
2704
}
2705

    
2706
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2707
{
2708
    FFStream *stream;
2709
    char path1[1024];
2710
    const char *path;
2711
    uint8_t *content;
2712
    int content_length, len;
2713
    struct sockaddr_in my_addr;
2714

    
2715
    /* find which url is asked */
2716
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2717
    path = path1;
2718
    if (*path == '/')
2719
        path++;
2720

    
2721
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2722
        if (!stream->is_feed && stream->fmt == &rtp_mux &&
2723
            !strcmp(path, stream->filename)) {
2724
            goto found;
2725
        }
2726
    }
2727
    /* no stream found */
2728
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2729
    return;
2730

    
2731
 found:
2732
    /* prepare the media description in sdp format */
2733

    
2734
    /* get the host IP */
2735
    len = sizeof(my_addr);
2736
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2737
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2738
    if (content_length < 0) {
2739
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2740
        return;
2741
    }
2742
    rtsp_reply_header(c, RTSP_STATUS_OK);
2743
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2744
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2745
    url_fprintf(c->pb, "\r\n");
2746
    put_buffer(c->pb, content, content_length);
2747
}
2748

    
2749
static HTTPContext *find_rtp_session(const char *session_id)
2750
{
2751
    HTTPContext *c;
2752

    
2753
    if (session_id[0] == '\0')
2754
        return NULL;
2755

    
2756
    for(c = first_http_ctx; c != NULL; c = c->next) {
2757
        if (!strcmp(c->session_id, session_id))
2758
            return c;
2759
    }
2760
    return NULL;
2761
}
2762

    
2763
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2764
{
2765
    RTSPTransportField *th;
2766
    int i;
2767

    
2768
    for(i=0;i<h->nb_transports;i++) {
2769
        th = &h->transports[i];
2770
        if (th->protocol == protocol)
2771
            return th;
2772
    }
2773
    return NULL;
2774
}
2775

    
2776
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2777
                           RTSPHeader *h)
2778
{
2779
    FFStream *stream;
2780
    int stream_index, port;
2781
    char buf[1024];
2782
    char path1[1024];
2783
    const char *path;
2784
    HTTPContext *rtp_c;
2785
    RTSPTransportField *th;
2786
    struct sockaddr_in dest_addr;
2787
    RTSPActionServerSetup setup;
2788

    
2789
    /* find which url is asked */
2790
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2791
    path = path1;
2792
    if (*path == '/')
2793
        path++;
2794

    
2795
    /* now check each stream */
2796
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2797
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2798
            /* accept aggregate filenames only if single stream */
2799
            if (!strcmp(path, stream->filename)) {
2800
                if (stream->nb_streams != 1) {
2801
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2802
                    return;
2803
                }
2804
                stream_index = 0;
2805
                goto found;
2806
            }
2807

    
2808
            for(stream_index = 0; stream_index < stream->nb_streams;
2809
                stream_index++) {
2810
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2811
                         stream->filename, stream_index);
2812
                if (!strcmp(path, buf))
2813
                    goto found;
2814
            }
2815
        }
2816
    }
2817
    /* no stream found */
2818
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2819
    return;
2820
 found:
2821

    
2822
    /* generate session id if needed */
2823
    if (h->session_id[0] == '\0') {
2824
        snprintf(h->session_id, sizeof(h->session_id),
2825
                 "%08x%08x", (int)random(), (int)random());
2826
    }
2827

    
2828
    /* find rtp session, and create it if none found */
2829
    rtp_c = find_rtp_session(h->session_id);
2830
    if (!rtp_c) {
2831
        /* always prefer UDP */
2832
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2833
        if (!th) {
2834
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2835
            if (!th) {
2836
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2837
                return;
2838
            }
2839
        }
2840

    
2841
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2842
                                   th->protocol);
2843
        if (!rtp_c) {
2844
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2845
            return;
2846
        }
2847

    
2848
        /* open input stream */
2849
        if (open_input_stream(rtp_c, "") < 0) {
2850
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2851
            return;
2852
        }
2853
    }
2854

    
2855
    /* test if stream is OK (test needed because several SETUP needs
2856
       to be done for a given file) */
2857
    if (rtp_c->stream != stream) {
2858
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2859
        return;
2860
    }
2861

    
2862
    /* test if stream is already set up */
2863
    if (rtp_c->rtp_ctx[stream_index]) {
2864
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2865
        return;
2866
    }
2867

    
2868
    /* check transport */
2869
    th = find_transport(h, rtp_c->rtp_protocol);
2870
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2871
                th->client_port_min <= 0)) {
2872
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2873
        return;
2874
    }
2875

    
2876
    /* setup default options */
2877
    setup.transport_option[0] = '\0';
2878
    dest_addr = rtp_c->from_addr;
2879
    dest_addr.sin_port = htons(th->client_port_min);
2880

    
2881
    /* add transport option if needed */
2882
    if (ff_rtsp_callback) {
2883
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2884
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2885
                             (char *)&setup, sizeof(setup),
2886
                             stream->rtsp_option) < 0) {
2887
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2888
            return;
2889
        }
2890
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2891
    }
2892

    
2893
    /* setup stream */
2894
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2895
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2896
        return;
2897
    }
2898

    
2899
    /* now everything is OK, so we can send the connection parameters */
2900
    rtsp_reply_header(c, RTSP_STATUS_OK);
2901
    /* session ID */
2902
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2903

    
2904
    switch(rtp_c->rtp_protocol) {
2905
    case RTSP_PROTOCOL_RTP_UDP:
2906
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2907
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2908
                    "client_port=%d-%d;server_port=%d-%d",
2909
                    th->client_port_min, th->client_port_min + 1,
2910
                    port, port + 1);
2911
        break;
2912
    case RTSP_PROTOCOL_RTP_TCP:
2913
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2914
                    stream_index * 2, stream_index * 2 + 1);
2915
        break;
2916
    default:
2917
        break;
2918
    }
2919
    if (setup.transport_option[0] != '\0') {
2920
        url_fprintf(c->pb, ";%s", setup.transport_option);
2921
    }
2922
    url_fprintf(c->pb, "\r\n");
2923

    
2924

    
2925
    url_fprintf(c->pb, "\r\n");
2926
}
2927

    
2928

    
2929
/* find an rtp connection by using the session ID. Check consistency
2930
   with filename */
2931
static HTTPContext *find_rtp_session_with_url(const char *url,
2932
                                              const char *session_id)
2933
{
2934
    HTTPContext *rtp_c;
2935
    char path1[1024];
2936
    const char *path;
2937
    char buf[1024];
2938
    int s;
2939

    
2940
    rtp_c = find_rtp_session(session_id);
2941
    if (!rtp_c)
2942
        return NULL;
2943

    
2944
    /* find which url is asked */
2945
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2946
    path = path1;
2947
    if (*path == '/')
2948
        path++;
2949
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2950
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2951
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2952
        rtp_c->stream->filename, s);
2953
      if(!strncmp(path, buf, sizeof(buf))) {
2954
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2955
        return rtp_c;
2956
      }
2957
    }
2958
    return NULL;
2959
}
2960

    
2961
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2962
{
2963
    HTTPContext *rtp_c;
2964

    
2965
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2966
    if (!rtp_c) {
2967
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2968
        return;
2969
    }
2970

    
2971
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2972
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2973
        rtp_c->state != HTTPSTATE_READY) {
2974
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2975
        return;
2976
    }
2977

    
2978
#if 0
2979
    /* XXX: seek in stream */
2980
    if (h->range_start != AV_NOPTS_VALUE) {
2981
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2982
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2983
    }
2984
#endif
2985

    
2986
    rtp_c->state = HTTPSTATE_SEND_DATA;
2987

    
2988
    /* now everything is OK, so we can send the connection parameters */
2989
    rtsp_reply_header(c, RTSP_STATUS_OK);
2990
    /* session ID */
2991
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2992
    url_fprintf(c->pb, "\r\n");
2993
}
2994

    
2995
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2996
{
2997
    HTTPContext *rtp_c;
2998

    
2999
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3000
    if (!rtp_c) {
3001
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3002
        return;
3003
    }
3004

    
3005
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3006
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3007
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3008
        return;
3009
    }
3010

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

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

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

    
3030
    /* abort the session */
3031
    close_connection(rtp_c);
3032

    
3033
    if (ff_rtsp_callback) {
3034
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3035
                         NULL, 0,
3036
                         rtp_c->stream->rtsp_option);
3037
    }
3038

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

    
3046

    
3047
/********************************************************************/
3048
/* RTP handling */
3049

    
3050
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3051
                                       FFStream *stream, const char *session_id,
3052
                                       enum RTSPProtocol rtp_protocol)
3053
{
3054
    HTTPContext *c = NULL;
3055
    const char *proto_str;
3056

    
3057
    /* XXX: should output a warning page when coming
3058
       close to the connection limit */
3059
    if (nb_connections >= nb_max_connections)
3060
        goto fail;
3061

    
3062
    /* add a new connection */
3063
    c = av_mallocz(sizeof(HTTPContext));
3064
    if (!c)
3065
        goto fail;
3066

    
3067
    c->fd = -1;
3068
    c->poll_entry = NULL;
3069
    c->from_addr = *from_addr;
3070
    c->buffer_size = IOBUFFER_INIT_SIZE;
3071
    c->buffer = av_malloc(c->buffer_size);
3072
    if (!c->buffer)
3073
        goto fail;
3074
    nb_connections++;
3075
    c->stream = stream;
3076
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3077
    c->state = HTTPSTATE_READY;
3078
    c->is_packetized = 1;
3079
    c->rtp_protocol = rtp_protocol;
3080

    
3081
    /* protocol is shown in statistics */
3082
    switch(c->rtp_protocol) {
3083
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3084
        proto_str = "MCAST";
3085
        break;
3086
    case RTSP_PROTOCOL_RTP_UDP:
3087
        proto_str = "UDP";
3088
        break;
3089
    case RTSP_PROTOCOL_RTP_TCP:
3090
        proto_str = "TCP";
3091
        break;
3092
    default:
3093
        proto_str = "???";
3094
        break;
3095
    }
3096
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3097
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3098

    
3099
    current_bandwidth += stream->bandwidth;
3100

    
3101
    c->next = first_http_ctx;
3102
    first_http_ctx = c;
3103
    return c;
3104

    
3105
 fail:
3106
    if (c) {
3107
        av_free(c->buffer);
3108
        av_free(c);
3109
    }
3110
    return NULL;
3111
}
3112

    
3113
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3114
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3115
   used. */
3116
static int rtp_new_av_stream(HTTPContext *c,
3117
                             int stream_index, struct sockaddr_in *dest_addr,
3118
                             HTTPContext *rtsp_c)
3119
{
3120
    AVFormatContext *ctx;
3121
    AVStream *st;
3122
    char *ipaddr;
3123
    URLContext *h;
3124
    uint8_t *dummy_buf;
3125
    char buf2[32];
3126
    int max_packet_size;
3127

    
3128
    /* now we can open the relevant output stream */
3129
    ctx = av_alloc_format_context();
3130
    if (!ctx)
3131
        return -1;
3132
    ctx->oformat = &rtp_mux;
3133

    
3134
    st = av_mallocz(sizeof(AVStream));
3135
    if (!st)
3136
        goto fail;
3137
    st->codec= avcodec_alloc_context();
3138
    ctx->nb_streams = 1;
3139
    ctx->streams[0] = st;
3140

    
3141
    if (!c->stream->feed ||
3142
        c->stream->feed == c->stream) {
3143
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3144
    } else {
3145
        memcpy(st,
3146
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3147
               sizeof(AVStream));
3148
    }
3149

    
3150
    /* build destination RTP address */
3151
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3152

    
3153
    switch(c->rtp_protocol) {
3154
    case RTSP_PROTOCOL_RTP_UDP:
3155
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3156
        /* RTP/UDP case */
3157

    
3158
        /* XXX: also pass as parameter to function ? */
3159
        if (c->stream->is_multicast) {
3160
            int ttl;
3161
            ttl = c->stream->multicast_ttl;
3162
            if (!ttl)
3163
                ttl = 16;
3164
            snprintf(ctx->filename, sizeof(ctx->filename),
3165
                     "rtp://%s:%d?multicast=1&ttl=%d",
3166
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3167
        } else {
3168
            snprintf(ctx->filename, sizeof(ctx->filename),
3169
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3170
        }
3171

    
3172
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3173
            goto fail;
3174
        c->rtp_handles[stream_index] = h;
3175
        max_packet_size = url_get_max_packet_size(h);
3176
        break;
3177
    case RTSP_PROTOCOL_RTP_TCP:
3178
        /* RTP/TCP case */
3179
        c->rtsp_c = rtsp_c;
3180
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3181
        break;
3182
    default:
3183
        goto fail;
3184
    }
3185

    
3186
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3187
             ipaddr, ntohs(dest_addr->sin_port),
3188
             ctime1(buf2),
3189
             c->stream->filename, stream_index, c->protocol);
3190

    
3191
    /* normally, no packets should be output here, but the packet size may be checked */
3192
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3193
        /* XXX: close stream */
3194
        goto fail;
3195
    }
3196
    av_set_parameters(ctx, NULL);
3197
    if (av_write_header(ctx) < 0) {
3198
    fail:
3199
        if (h)
3200
            url_close(h);
3201
        av_free(ctx);
3202
        return -1;
3203
    }
3204
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3205
    av_free(dummy_buf);
3206

    
3207
    c->rtp_ctx[stream_index] = ctx;
3208
    return 0;
3209
}
3210

    
3211
/********************************************************************/
3212
/* ffserver initialization */
3213

    
3214
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3215
{
3216
    AVStream *fst;
3217

    
3218
    fst = av_mallocz(sizeof(AVStream));
3219
    if (!fst)
3220
        return NULL;
3221
    fst->codec= avcodec_alloc_context();
3222
    fst->priv_data = av_mallocz(sizeof(FeedData));
3223
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3224
    fst->codec->coded_frame = &dummy_frame;
3225
    fst->index = stream->nb_streams;
3226
    av_set_pts_info(fst, 33, 1, 90000);
3227
    stream->streams[stream->nb_streams++] = fst;
3228
    return fst;
3229
}
3230

    
3231
/* return the stream number in the feed */
3232
static int add_av_stream(FFStream *feed, AVStream *st)
3233
{
3234
    AVStream *fst;
3235
    AVCodecContext *av, *av1;
3236
    int i;
3237

    
3238
    av = st->codec;
3239
    for(i=0;i<feed->nb_streams;i++) {
3240
        st = feed->streams[i];
3241
        av1 = st->codec;
3242
        if (av1->codec_id == av->codec_id &&
3243
            av1->codec_type == av->codec_type &&
3244
            av1->bit_rate == av->bit_rate) {
3245

    
3246
            switch(av->codec_type) {
3247
            case CODEC_TYPE_AUDIO:
3248
                if (av1->channels == av->channels &&
3249
                    av1->sample_rate == av->sample_rate)
3250
                    goto found;
3251
                break;
3252
            case CODEC_TYPE_VIDEO:
3253
                if (av1->width == av->width &&
3254
                    av1->height == av->height &&
3255
                    av1->time_base.den == av->time_base.den &&
3256
                    av1->time_base.num == av->time_base.num &&
3257
                    av1->gop_size == av->gop_size)
3258
                    goto found;
3259
                break;
3260
            default:
3261
                av_abort();
3262
            }
3263
        }
3264
    }
3265

    
3266
    fst = add_av_stream1(feed, av);
3267
    if (!fst)
3268
        return -1;
3269
    return feed->nb_streams - 1;
3270
 found:
3271
    return i;
3272
}
3273

    
3274
static void remove_stream(FFStream *stream)
3275
{
3276
    FFStream **ps;
3277
    ps = &first_stream;
3278
    while (*ps != NULL) {
3279
        if (*ps == stream) {
3280
            *ps = (*ps)->next;
3281
        } else {
3282
            ps = &(*ps)->next;
3283
        }
3284
    }
3285
}
3286

    
3287
/* specific mpeg4 handling : we extract the raw parameters */
3288
static void extract_mpeg4_header(AVFormatContext *infile)
3289
{
3290
    int mpeg4_count, i, size;
3291
    AVPacket pkt;
3292
    AVStream *st;
3293
    const uint8_t *p;
3294

    
3295
    mpeg4_count = 0;
3296
    for(i=0;i<infile->nb_streams;i++) {
3297
        st = infile->streams[i];
3298
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3299
            st->codec->extradata_size == 0) {
3300
            mpeg4_count++;
3301
        }
3302
    }
3303
    if (!mpeg4_count)
3304
        return;
3305

    
3306
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3307
    while (mpeg4_count > 0) {
3308
        if (av_read_packet(infile, &pkt) < 0)
3309
            break;
3310
        st = infile->streams[pkt.stream_index];
3311
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3312
            st->codec->extradata_size == 0) {
3313
            av_freep(&st->codec->extradata);
3314
            /* fill extradata with the header */
3315
            /* XXX: we make hard suppositions here ! */
3316
            p = pkt.data;
3317
            while (p < pkt.data + pkt.size - 4) {
3318
                /* stop when vop header is found */
3319
                if (p[0] == 0x00 && p[1] == 0x00 &&
3320
                    p[2] == 0x01 && p[3] == 0xb6) {
3321
                    size = p - pkt.data;
3322
                    //                    av_hex_dump(pkt.data, size);
3323
                    st->codec->extradata = av_malloc(size);
3324
                    st->codec->extradata_size = size;
3325
                    memcpy(st->codec->extradata, pkt.data, size);
3326
                    break;
3327
                }
3328
                p++;
3329
            }
3330
            mpeg4_count--;
3331
        }
3332
        av_free_packet(&pkt);
3333
    }
3334
}
3335

    
3336
/* compute the needed AVStream for each file */
3337
static void build_file_streams(void)
3338
{
3339
    FFStream *stream, *stream_next;
3340
    AVFormatContext *infile;
3341
    int i;
3342

    
3343
    /* gather all streams */
3344
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3345
        stream_next = stream->next;
3346
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3347
            !stream->feed) {
3348
            /* the stream comes from a file */
3349
            /* try to open the file */
3350
            /* open stream */
3351
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3352
            if (stream->fmt == &rtp_mux) {
3353
                /* specific case : if transport stream output to RTP,
3354
                   we use a raw transport stream reader */
3355
                stream->ap_in->mpeg2ts_raw = 1;
3356
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3357
            }
3358

    
3359
            if (av_open_input_file(&infile, stream->feed_filename,
3360
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3361
                http_log("%s not found", stream->feed_filename);
3362
                /* remove stream (no need to spend more time on it) */
3363
            fail:
3364
                remove_stream(stream);
3365
            } else {
3366
                /* find all the AVStreams inside and reference them in
3367
                   'stream' */
3368
                if (av_find_stream_info(infile) < 0) {
3369
                    http_log("Could not find codec parameters from '%s'",
3370
                             stream->feed_filename);
3371
                    av_close_input_file(infile);
3372
                    goto fail;
3373
                }
3374
                extract_mpeg4_header(infile);
3375

    
3376
                for(i=0;i<infile->nb_streams;i++) {
3377
                    add_av_stream1(stream, infile->streams[i]->codec);
3378
                }
3379
                av_close_input_file(infile);
3380
            }
3381
        }
3382
    }
3383
}
3384

    
3385
/* compute the needed AVStream for each feed */
3386
static void build_feed_streams(void)
3387
{
3388
    FFStream *stream, *feed;
3389
    int i;
3390

    
3391
    /* gather all streams */
3392
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3393
        feed = stream->feed;
3394
        if (feed) {
3395
            if (!stream->is_feed) {
3396
                /* we handle a stream coming from a feed */
3397
                for(i=0;i<stream->nb_streams;i++) {
3398
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3399
                }
3400
            }
3401
        }
3402
    }
3403

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

    
3416
    /* create feed files if needed */
3417
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3418
        int fd;
3419

    
3420
        if (url_exist(feed->feed_filename)) {
3421
            /* See if it matches */
3422
            AVFormatContext *s;
3423
            int matches = 0;
3424

    
3425
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3426
                /* Now see if it matches */
3427
                if (s->nb_streams == feed->nb_streams) {
3428
                    matches = 1;
3429
                    for(i=0;i<s->nb_streams;i++) {
3430
                        AVStream *sf, *ss;
3431
                        sf = feed->streams[i];
3432
                        ss = s->streams[i];
3433

    
3434
                        if (sf->index != ss->index ||
3435
                            sf->id != ss->id) {
3436
                            printf("Index & Id do not match for stream %d (%s)\n",
3437
                                   i, feed->feed_filename);
3438
                            matches = 0;
3439
                        } else {
3440
                            AVCodecContext *ccf, *ccs;
3441

    
3442
                            ccf = sf->codec;
3443
                            ccs = ss->codec;
3444
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3445

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

    
3481
                av_close_input_file(s);
3482
            } else {
3483
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3484
                        feed->feed_filename);
3485
            }
3486
            if (!matches) {
3487
                if (feed->readonly) {
3488
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3489
                        feed->feed_filename);
3490
                    exit(1);
3491
                }
3492
                unlink(feed->feed_filename);
3493
            }
3494
        }
3495
        if (!url_exist(feed->feed_filename)) {
3496
            AVFormatContext s1, *s = &s1;
3497

    
3498
            if (feed->readonly) {
3499
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3500
                    feed->feed_filename);
3501
                exit(1);
3502
            }
3503

    
3504
            /* only write the header of the ffm file */
3505
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3506
                fprintf(stderr, "Could not open output feed file '%s'\n",
3507
                        feed->feed_filename);
3508
                exit(1);
3509
            }
3510
            s->oformat = feed->fmt;
3511
            s->nb_streams = feed->nb_streams;
3512
            for(i=0;i<s->nb_streams;i++) {
3513
                AVStream *st;
3514
                st = feed->streams[i];
3515
                s->streams[i] = st;
3516
            }
3517
            av_set_parameters(s, NULL);
3518
            av_write_header(s);
3519
            /* XXX: need better api */
3520
            av_freep(&s->priv_data);
3521
            url_fclose(&s->pb);
3522
        }
3523
        /* get feed size and write index */
3524
        fd = open(feed->feed_filename, O_RDONLY);
3525
        if (fd < 0) {
3526
            fprintf(stderr, "Could not open output feed file '%s'\n",
3527
                    feed->feed_filename);
3528
            exit(1);
3529
        }
3530

    
3531
        feed->feed_write_index = ffm_read_write_index(fd);
3532
        feed->feed_size = lseek(fd, 0, SEEK_END);
3533
        /* ensure that we do not wrap before the end of file */
3534
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3535
            feed->feed_max_size = feed->feed_size;
3536

    
3537
        close(fd);
3538
    }
3539
}
3540

    
3541
/* compute the bandwidth used by each stream */
3542
static void compute_bandwidth(void)
3543
{
3544
    int bandwidth, i;
3545
    FFStream *stream;
3546

    
3547
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3548
        bandwidth = 0;
3549
        for(i=0;i<stream->nb_streams;i++) {
3550
            AVStream *st = stream->streams[i];
3551
            switch(st->codec->codec_type) {
3552
            case CODEC_TYPE_AUDIO:
3553
            case CODEC_TYPE_VIDEO:
3554
                bandwidth += st->codec->bit_rate;
3555
                break;
3556
            default:
3557
                break;
3558
            }
3559
        }
3560
        stream->bandwidth = (bandwidth + 999) / 1000;
3561
    }
3562
}
3563

    
3564
static void get_arg(char *buf, int buf_size, const char **pp)
3565
{
3566
    const char *p;
3567
    char *q;
3568
    int quote;
3569

    
3570
    p = *pp;
3571
    while (isspace(*p)) p++;
3572
    q = buf;
3573
    quote = 0;
3574
    if (*p == '\"' || *p == '\'')
3575
        quote = *p++;
3576
    for(;;) {
3577
        if (quote) {
3578
            if (*p == quote)
3579
                break;
3580
        } else {
3581
            if (isspace(*p))
3582
                break;
3583
        }
3584
        if (*p == '\0')
3585
            break;
3586
        if ((q - buf) < buf_size - 1)
3587
            *q++ = *p;
3588
        p++;
3589
    }
3590
    *q = '\0';
3591
    if (quote && *p == quote)
3592
        p++;
3593
    *pp = p;
3594
}
3595

    
3596
/* add a codec and set the default parameters */
3597
static void add_codec(FFStream *stream, AVCodecContext *av)
3598
{
3599
    AVStream *st;
3600

    
3601
    /* compute default parameters */
3602
    switch(av->codec_type) {
3603
    case CODEC_TYPE_AUDIO:
3604
        if (av->bit_rate == 0)
3605
            av->bit_rate = 64000;
3606
        if (av->sample_rate == 0)
3607
            av->sample_rate = 22050;
3608
        if (av->channels == 0)
3609
            av->channels = 1;
3610
        break;
3611
    case CODEC_TYPE_VIDEO:
3612
        if (av->bit_rate == 0)
3613
            av->bit_rate = 64000;
3614
        if (av->time_base.num == 0){
3615
            av->time_base.den = 5;
3616
            av->time_base.num = 1;
3617
        }
3618
        if (av->width == 0 || av->height == 0) {
3619
            av->width = 160;
3620
            av->height = 128;
3621
        }
3622
        /* Bitrate tolerance is less for streaming */
3623
        if (av->bit_rate_tolerance == 0)
3624
            av->bit_rate_tolerance = av->bit_rate / 4;
3625
        if (av->qmin == 0)
3626
            av->qmin = 3;
3627
        if (av->qmax == 0)
3628
            av->qmax = 31;
3629
        if (av->max_qdiff == 0)
3630
            av->max_qdiff = 3;
3631
        av->qcompress = 0.5;
3632
        av->qblur = 0.5;
3633

    
3634
        if (!av->nsse_weight)
3635
            av->nsse_weight = 8;
3636

    
3637
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3638
        av->me_method = ME_EPZS;
3639
        av->rc_buffer_aggressivity = 1.0;
3640

    
3641
        if (!av->rc_eq)
3642
            av->rc_eq = "tex^qComp";
3643
        if (!av->i_quant_factor)
3644
            av->i_quant_factor = -0.8;
3645
        if (!av->b_quant_factor)
3646
            av->b_quant_factor = 1.25;
3647
        if (!av->b_quant_offset)
3648
            av->b_quant_offset = 1.25;
3649
        if (!av->rc_max_rate)
3650
            av->rc_max_rate = av->bit_rate * 2;
3651

    
3652
        if (av->rc_max_rate && !av->rc_buffer_size) {
3653
            av->rc_buffer_size = av->rc_max_rate;
3654
        }
3655

    
3656

    
3657
        break;
3658
    default:
3659
        av_abort();
3660
    }
3661

    
3662
    st = av_mallocz(sizeof(AVStream));
3663
    if (!st)
3664
        return;
3665
    st->codec = avcodec_alloc_context();
3666
    stream->streams[stream->nb_streams++] = st;
3667
    memcpy(st->codec, av, sizeof(AVCodecContext));
3668
}
3669

    
3670
static int opt_audio_codec(const char *arg)
3671
{
3672
    AVCodec *p;
3673

    
3674
    p = first_avcodec;
3675
    while (p) {
3676
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3677
            break;
3678
        p = p->next;
3679
    }
3680
    if (p == NULL) {
3681
        return CODEC_ID_NONE;
3682
    }
3683

    
3684
    return p->id;
3685
}
3686

    
3687
static int opt_video_codec(const char *arg)
3688
{
3689
    AVCodec *p;
3690

    
3691
    p = first_avcodec;
3692
    while (p) {
3693
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3694
            break;
3695
        p = p->next;
3696
    }
3697
    if (p == NULL) {
3698
        return CODEC_ID_NONE;
3699
    }
3700

    
3701
    return p->id;
3702
}
3703

    
3704
/* simplistic plugin support */
3705

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

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

    
3726
    init_func();
3727
}
3728
#endif
3729

    
3730
static int parse_ffconfig(const char *filename)
3731
{
3732
    FILE *f;
3733
    char line[1024];
3734
    char cmd[64];
3735
    char arg[1024];
3736
    const char *p;
3737
    int val, errors, line_num;
3738
    FFStream **last_stream, *stream, *redirect;
3739
    FFStream **last_feed, *feed;
3740
    AVCodecContext audio_enc, video_enc;
3741
    int audio_id, video_id;
3742

    
3743
    f = fopen(filename, "r");
3744
    if (!f) {
3745
        perror(filename);
3746
        return -1;
3747
    }
3748

    
3749
    errors = 0;
3750
    line_num = 0;
3751
    first_stream = NULL;
3752
    last_stream = &first_stream;
3753
    first_feed = NULL;
3754
    last_feed = &first_feed;
3755
    stream = NULL;
3756
    feed = NULL;
3757
    redirect = NULL;
3758
    audio_id = CODEC_ID_NONE;
3759
    video_id = CODEC_ID_NONE;
3760
    for(;;) {
3761
        if (fgets(line, sizeof(line), f) == NULL)
3762
            break;
3763
        line_num++;
3764
        p = line;
3765
        while (isspace(*p))
3766
            p++;
3767
        if (*p == '\0' || *p == '#')
3768
            continue;
3769

    
3770
        get_arg(cmd, sizeof(cmd), &p);
3771

    
3772
        if (!strcasecmp(cmd, "Port")) {
3773
            get_arg(arg, sizeof(arg), &p);
3774
            my_http_addr.sin_port = htons (atoi(arg));
3775
        } else if (!strcasecmp(cmd, "BindAddress")) {
3776
            get_arg(arg, sizeof(arg), &p);
3777
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3778
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3779
                        filename, line_num, arg);
3780
                errors++;
3781
            }
3782
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3783
            ffserver_daemon = 0;
3784
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3785
            get_arg(arg, sizeof(arg), &p);
3786
            my_rtsp_addr.sin_port = htons (atoi(arg));
3787
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3788
            get_arg(arg, sizeof(arg), &p);
3789
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3790
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3791
                        filename, line_num, arg);
3792
                errors++;
3793
            }
3794
        } else if (!strcasecmp(cmd, "MaxClients")) {
3795
            get_arg(arg, sizeof(arg), &p);
3796
            val = atoi(arg);
3797
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3798
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3799
                        filename, line_num, arg);
3800
                errors++;
3801
            } else {
3802
                nb_max_connections = val;
3803
            }
3804
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3805
            get_arg(arg, sizeof(arg), &p);
3806
            val = atoi(arg);
3807
            if (val < 10 || val > 100000) {
3808
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3809
                        filename, line_num, arg);
3810
                errors++;
3811
            } else {
3812
                max_bandwidth = val;
3813
            }
3814
        } else if (!strcasecmp(cmd, "CustomLog")) {
3815
            get_arg(logfilename, sizeof(logfilename), &p);
3816
        } else if (!strcasecmp(cmd, "<Feed")) {
3817
            /*********************************************/
3818
            /* Feed related options */
3819
            char *q;
3820
            if (stream || feed) {
3821
                fprintf(stderr, "%s:%d: Already in a tag\n",
3822
                        filename, line_num);
3823
            } else {
3824
                feed = av_mallocz(sizeof(FFStream));
3825
                /* add in stream list */
3826
                *last_stream = feed;
3827
                last_stream = &feed->next;
3828
                /* add in feed list */
3829
                *last_feed = feed;
3830
                last_feed = &feed->next_feed;
3831

    
3832
                get_arg(feed->filename, sizeof(feed->filename), &p);
3833
                q = strrchr(feed->filename, '>');
3834
                if (*q)
3835
                    *q = '\0';
3836
                feed->fmt = guess_format("ffm", NULL, NULL);
3837
                /* defaut feed file */
3838
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3839
                         "/tmp/%s.ffm", feed->filename);
3840
                feed->feed_max_size = 5 * 1024 * 1024;
3841
                feed->is_feed = 1;
3842
                feed->feed = feed; /* self feeding :-) */
3843
            }
3844
        } else if (!strcasecmp(cmd, "Launch")) {
3845
            if (feed) {
3846
                int i;
3847

    
3848
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3849

    
3850
                for (i = 0; i < 62; i++) {
3851
                    char argbuf[256];
3852

    
3853
                    get_arg(argbuf, sizeof(argbuf), &p);
3854
                    if (!argbuf[0])
3855
                        break;
3856

    
3857
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3858
                    strcpy(feed->child_argv[i], argbuf);
3859
                }
3860

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

    
3863
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3864
                    "http://%s:%d/%s",
3865
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3866
                    inet_ntoa(my_http_addr.sin_addr),
3867
                    ntohs(my_http_addr.sin_port), feed->filename);
3868

    
3869
                if (ffserver_debug)
3870
                {
3871
                    int j;
3872
                    fprintf(stdout, "Launch commandline: ");
3873
                    for (j = 0; j <= i; j++)
3874
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3875
                    fprintf(stdout, "\n");
3876
                }
3877
            }
3878
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3879
            if (feed) {
3880
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3881
                feed->readonly = 1;
3882
            } else if (stream) {
3883
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3884
            }
3885
        } else if (!strcasecmp(cmd, "File")) {
3886
            if (feed) {
3887
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3888
            } else if (stream) {
3889
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3890
            }
3891
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3892
            if (feed) {
3893
                const char *p1;
3894
                double fsize;
3895

    
3896
                get_arg(arg, sizeof(arg), &p);
3897
                p1 = arg;
3898
                fsize = strtod(p1, (char **)&p1);
3899
                switch(toupper(*p1)) {
3900
                case 'K':
3901
                    fsize *= 1024;
3902
                    break;
3903
                case 'M':
3904
                    fsize *= 1024 * 1024;
3905
                    break;
3906
                case 'G':
3907
                    fsize *= 1024 * 1024 * 1024;
3908
                    break;
3909
                }
3910
                feed->feed_max_size = (int64_t)fsize;
3911
            }
3912
        } else if (!strcasecmp(cmd, "</Feed>")) {
3913
            if (!feed) {
3914
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3915
                        filename, line_num);
3916
                errors++;
3917
#if 0
3918
            } else {
3919
                /* Make sure that we start out clean */
3920
                if (unlink(feed->feed_filename) < 0
3921
                    && errno != ENOENT) {
3922
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3923
                        filename, line_num, feed->feed_filename, strerror(errno));
3924
                    errors++;
3925
                }
3926
#endif
3927
            }
3928
            feed = NULL;
3929
        } else if (!strcasecmp(cmd, "<Stream")) {
3930
            /*********************************************/
3931
            /* Stream related options */
3932
            char *q;
3933
            if (stream || feed) {
3934
                fprintf(stderr, "%s:%d: Already in a tag\n",
3935
                        filename, line_num);
3936
            } else {
3937
                stream = av_mallocz(sizeof(FFStream));
3938
                *last_stream = stream;
3939
                last_stream = &stream->next;
3940

    
3941
                get_arg(stream->filename, sizeof(stream->filename), &p);
3942
                q = strrchr(stream->filename, '>');
3943
                if (*q)
3944
                    *q = '\0';
3945
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3946
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3947
                memset(&video_enc, 0, sizeof(AVCodecContext));
3948
                audio_id = CODEC_ID_NONE;
3949
                video_id = CODEC_ID_NONE;
3950
                if (stream->fmt) {
3951
                    audio_id = stream->fmt->audio_codec;
3952
                    video_id = stream->fmt->video_codec;
3953
                }
3954
            }
3955
        } else if (!strcasecmp(cmd, "Feed")) {
3956
            get_arg(arg, sizeof(arg), &p);
3957
            if (stream) {
3958
                FFStream *sfeed;
3959

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

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

    
4080
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4081
                    video_enc.rc_min_rate = minrate * 1000;
4082
                    video_enc.rc_max_rate = maxrate * 1000;
4083
                } else {
4084
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4085
                            filename, line_num, arg);
4086
                    errors++;
4087
                }
4088
            }
4089
        } else if (!strcasecmp(cmd, "Debug")) {
4090
            if (stream) {
4091
                get_arg(arg, sizeof(arg), &p);
4092
                video_enc.debug = strtol(arg,0,0);
4093
            }
4094
        } else if (!strcasecmp(cmd, "Strict")) {
4095
            if (stream) {
4096
                get_arg(arg, sizeof(arg), &p);
4097
                video_enc.strict_std_compliance = atoi(arg);
4098
            }
4099
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4100
            if (stream) {
4101
                get_arg(arg, sizeof(arg), &p);
4102
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4103
            }
4104
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4105
            if (stream) {
4106
                get_arg(arg, sizeof(arg), &p);
4107
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4108
            }
4109
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4110
            get_arg(arg, sizeof(arg), &p);
4111
            if (stream) {
4112
                video_enc.bit_rate = atoi(arg) * 1000;
4113
            }
4114
        } else if (!strcasecmp(cmd, "VideoSize")) {
4115
            get_arg(arg, sizeof(arg), &p);
4116
            if (stream) {
4117
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4118
                if ((video_enc.width % 16) != 0 ||
4119
                    (video_enc.height % 16) != 0) {
4120
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4121
                            filename, line_num);
4122
                    errors++;
4123
                }
4124
            }
4125
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4126
            get_arg(arg, sizeof(arg), &p);
4127
            if (stream) {
4128
                video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4129
                video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4130
            }
4131
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4132
            get_arg(arg, sizeof(arg), &p);
4133
            if (stream) {
4134
                video_enc.gop_size = atoi(arg);
4135
            }
4136
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4137
            if (stream) {
4138
                video_enc.gop_size = 1;
4139
            }
4140
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4141
            if (stream) {
4142
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4143
            }
4144
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4145
            if (stream) {
4146
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4147
                video_enc.flags |= CODEC_FLAG_4MV;
4148
            }
4149
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4150
            get_arg(arg, sizeof(arg), &p);
4151
            if (stream) {
4152
                video_enc.max_qdiff = atoi(arg);
4153
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4154
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4155
                            filename, line_num);
4156
                    errors++;
4157
                }
4158
            }
4159
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4160
            get_arg(arg, sizeof(arg), &p);
4161
            if (stream) {
4162
                video_enc.qmax = atoi(arg);
4163
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4164
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4165
                            filename, line_num);
4166
                    errors++;
4167
                }
4168
            }
4169
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4170
            get_arg(arg, sizeof(arg), &p);
4171
            if (stream) {
4172
                video_enc.qmin = atoi(arg);
4173
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4174
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4175
                            filename, line_num);
4176
                    errors++;
4177
                }
4178
            }
4179
        } else if (!strcasecmp(cmd, "LumaElim")) {
4180
            get_arg(arg, sizeof(arg), &p);
4181
            if (stream) {
4182
                video_enc.luma_elim_threshold = atoi(arg);
4183
            }
4184
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4185
            get_arg(arg, sizeof(arg), &p);
4186
            if (stream) {
4187
                video_enc.chroma_elim_threshold = atoi(arg);
4188
            }
4189
        } else if (!strcasecmp(cmd, "LumiMask")) {
4190
            get_arg(arg, sizeof(arg), &p);
4191
            if (stream) {
4192
                video_enc.lumi_masking = atof(arg);
4193
            }
4194
        } else if (!strcasecmp(cmd, "DarkMask")) {
4195
            get_arg(arg, sizeof(arg), &p);
4196
            if (stream) {
4197
                video_enc.dark_masking = atof(arg);
4198
            }
4199
        } else if (!strcasecmp(cmd, "NoVideo")) {
4200
            video_id = CODEC_ID_NONE;
4201
        } else if (!strcasecmp(cmd, "NoAudio")) {
4202
            audio_id = CODEC_ID_NONE;
4203
        } else if (!strcasecmp(cmd, "ACL")) {
4204
            IPAddressACL acl;
4205
            struct hostent *he;
4206

    
4207
            get_arg(arg, sizeof(arg), &p);
4208
            if (strcasecmp(arg, "allow") == 0) {
4209
                acl.action = IP_ALLOW;
4210
            } else if (strcasecmp(arg, "deny") == 0) {
4211
                acl.action = IP_DENY;
4212
            } else {
4213
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4214
                        filename, line_num, arg);
4215
                errors++;
4216
            }
4217

    
4218
            get_arg(arg, sizeof(arg), &p);
4219

    
4220
            he = gethostbyname(arg);
4221
            if (!he) {
4222
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4223
                        filename, line_num, arg);
4224
                errors++;
4225
            } else {
4226
                /* Only take the first */
4227
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4228
                acl.last = acl.first;
4229
            }
4230

    
4231
            get_arg(arg, sizeof(arg), &p);
4232

    
4233
            if (arg[0]) {
4234
                he = gethostbyname(arg);
4235
                if (!he) {
4236
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4237
                            filename, line_num, arg);
4238
                    errors++;
4239
                } else {
4240
                    /* Only take the first */
4241
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4242
                }
4243
            }
4244

    
4245
            if (!errors) {
4246
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4247
                IPAddressACL **naclp = 0;
4248

    
4249
                *nacl = acl;
4250
                nacl->next = 0;
4251

    
4252
                if (stream) {
4253
                    naclp = &stream->acl;
4254
                } else if (feed) {
4255
                    naclp = &feed->acl;
4256
                } else {
4257
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4258
                            filename, line_num);
4259
                    errors++;
4260
                }
4261

    
4262
                if (naclp) {
4263
                    while (*naclp)
4264
                        naclp = &(*naclp)->next;
4265

    
4266
                    *naclp = nacl;
4267
                }
4268
            }
4269
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4270
            get_arg(arg, sizeof(arg), &p);
4271
            if (stream) {
4272
                av_freep(&stream->rtsp_option);
4273
                /* XXX: av_strdup ? */
4274
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
4275
                if (stream->rtsp_option) {
4276
                    strcpy(stream->rtsp_option, arg);
4277
                }
4278
            }
4279
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4280
            get_arg(arg, sizeof(arg), &p);
4281
            if (stream) {
4282
                if (!inet_aton(arg, &stream->multicast_ip)) {
4283
                    fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
4284
                            filename, line_num, arg);
4285
                    errors++;
4286
                }
4287
                stream->is_multicast = 1;
4288
                stream->loop = 1; /* default is looping */
4289
            }
4290
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4291
            get_arg(arg, sizeof(arg), &p);
4292
            if (stream) {
4293
                stream->multicast_port = atoi(arg);
4294
            }
4295
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4296
            get_arg(arg, sizeof(arg), &p);
4297
            if (stream) {
4298
                stream->multicast_ttl = atoi(arg);
4299
            }
4300
        } else if (!strcasecmp(cmd, "NoLoop")) {
4301
            if (stream) {
4302
                stream->loop = 0;
4303
            }
4304
        } else if (!strcasecmp(cmd, "</Stream>")) {
4305
            if (!stream) {
4306
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4307
                        filename, line_num);
4308
                errors++;
4309
            }
4310
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4311
                if (audio_id != CODEC_ID_NONE) {
4312
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
4313
                    audio_enc.codec_id = audio_id;
4314
                    add_codec(stream, &audio_enc);
4315
                }
4316
                if (video_id != CODEC_ID_NONE) {
4317
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
4318
                    video_enc.codec_id = video_id;
4319
                    add_codec(stream, &video_enc);
4320
                }
4321
            }
4322
            stream = NULL;
4323
        } else if (!strcasecmp(cmd, "<Redirect")) {
4324
            /*********************************************/
4325
            char *q;
4326
            if (stream || feed || redirect) {
4327
                fprintf(stderr, "%s:%d: Already in a tag\n",
4328
                        filename, line_num);
4329
                errors++;
4330
            } else {
4331
                redirect = av_mallocz(sizeof(FFStream));
4332
                *last_stream = redirect;
4333
                last_stream = &redirect->next;
4334

    
4335
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4336
                q = strrchr(redirect->filename, '>');
4337
                if (*q)
4338
                    *q = '\0';
4339
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4340
            }
4341
        } else if (!strcasecmp(cmd, "URL")) {
4342
            if (redirect) {
4343
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4344
            }
4345
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4346
            if (!redirect) {
4347
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4348
                        filename, line_num);
4349
                errors++;
4350
            }
4351
            if (!redirect->feed_filename[0]) {
4352
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4353
                        filename, line_num);
4354
                errors++;
4355
            }
4356
            redirect = NULL;
4357
        } else if (!strcasecmp(cmd, "LoadModule")) {
4358
            get_arg(arg, sizeof(arg), &p);
4359
#ifdef CONFIG_HAVE_DLOPEN
4360
            load_module(arg);
4361
#else
4362
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4363
                    filename, line_num, arg);
4364
            errors++;
4365
#endif
4366
        } else {
4367
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4368
                    filename, line_num, cmd);
4369
            errors++;
4370
        }
4371
    }
4372

    
4373
    fclose(f);
4374
    if (errors)
4375
        return -1;
4376
    else
4377
        return 0;
4378
}
4379

    
4380

    
4381
#if 0
4382
static void write_packet(FFCodec *ffenc,
4383
                         uint8_t *buf, int size)
4384
{
4385
    PacketHeader hdr;
4386
    AVCodecContext *enc = &ffenc->enc;
4387
    uint8_t *wptr;
4388
    mk_header(&hdr, enc, size);
4389
    wptr = http_fifo.wptr;
4390
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4391
    fifo_write(&http_fifo, buf, size, &wptr);
4392
    /* atomic modification of wptr */
4393
    http_fifo.wptr = wptr;
4394
    ffenc->data_count += size;
4395
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4396
}
4397
#endif
4398

    
4399
static void show_banner(void)
4400
{
4401
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4402
}
4403

    
4404
static void show_help(void)
4405
{
4406
    show_banner();
4407
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4408
           "Hyper fast multi format Audio/Video streaming server\n"
4409
           "\n"
4410
           "-L            : print the LICENSE\n"
4411
           "-h            : this help\n"
4412
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4413
           );
4414
}
4415

    
4416
static void show_license(void)
4417
{
4418
    show_banner();
4419
    printf(
4420
    "This library is free software; you can redistribute it and/or\n"
4421
    "modify it under the terms of the GNU Lesser General Public\n"
4422
    "License as published by the Free Software Foundation; either\n"
4423
    "version 2 of the License, or (at your option) any later version.\n"
4424
    "\n"
4425
    "This library is distributed in the hope that it will be useful,\n"
4426
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4427
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4428
    "Lesser General Public License for more details.\n"
4429
    "\n"
4430
    "You should have received a copy of the GNU Lesser General Public\n"
4431
    "License along with this library; if not, write to the Free Software\n"
4432
    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
4433
    );
4434
}
4435

    
4436
static void handle_child_exit(int sig)
4437
{
4438
    pid_t pid;
4439
    int status;
4440

    
4441
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4442
        FFStream *feed;
4443

    
4444
        for (feed = first_feed; feed; feed = feed->next) {
4445
            if (feed->pid == pid) {
4446
                int uptime = time(0) - feed->pid_start;
4447

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

    
4451
                if (uptime < 30) {
4452
                    /* Turn off any more restarts */
4453
                    feed->child_argv = 0;
4454
                }
4455
            }
4456
        }
4457
    }
4458

    
4459
    need_to_start_children = 1;
4460
}
4461

    
4462
int main(int argc, char **argv)
4463
{
4464
    const char *config_filename;
4465
    int c;
4466
    struct sigaction sigact;
4467

    
4468
    av_register_all();
4469

    
4470
    config_filename = "/etc/ffserver.conf";
4471

    
4472
    my_program_name = argv[0];
4473
    my_program_dir = getcwd(0, 0);
4474
    ffserver_daemon = 1;
4475

    
4476
    for(;;) {
4477
        c = getopt(argc, argv, "ndLh?f:");
4478
        if (c == -1)
4479
            break;
4480
        switch(c) {
4481
        case 'L':
4482
            show_license();
4483
            exit(1);
4484
        case '?':
4485
        case 'h':
4486
            show_help();
4487
            exit(1);
4488
        case 'n':
4489
            no_launch = 1;
4490
            break;
4491
        case 'd':
4492
            ffserver_debug = 1;
4493
            ffserver_daemon = 0;
4494
            break;
4495
        case 'f':
4496
            config_filename = optarg;
4497
            break;
4498
        default:
4499
            exit(2);
4500
        }
4501
    }
4502

    
4503
    putenv("http_proxy");               /* Kill the http_proxy */
4504

    
4505
    srandom(gettime_ms() + (getpid() << 16));
4506

    
4507
    /* address on which the server will handle HTTP connections */
4508
    my_http_addr.sin_family = AF_INET;
4509
    my_http_addr.sin_port = htons (8080);
4510
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4511

    
4512
    /* address on which the server will handle RTSP connections */
4513
    my_rtsp_addr.sin_family = AF_INET;
4514
    my_rtsp_addr.sin_port = htons (5454);
4515
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4516

    
4517
    nb_max_connections = 5;
4518
    max_bandwidth = 1000;
4519
    first_stream = NULL;
4520
    logfilename[0] = '\0';
4521

    
4522
    memset(&sigact, 0, sizeof(sigact));
4523
    sigact.sa_handler = handle_child_exit;
4524
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4525
    sigaction(SIGCHLD, &sigact, 0);
4526

    
4527
    if (parse_ffconfig(config_filename) < 0) {
4528
        fprintf(stderr, "Incorrect config file - exiting.\n");
4529
        exit(1);
4530
    }
4531

    
4532
    build_file_streams();
4533

    
4534
    build_feed_streams();
4535

    
4536
    compute_bandwidth();
4537

    
4538
    /* put the process in background and detach it from its TTY */
4539
    if (ffserver_daemon) {
4540
        int pid;
4541

    
4542
        pid = fork();
4543
        if (pid < 0) {
4544
            perror("fork");
4545
            exit(1);
4546
        } else if (pid > 0) {
4547
            /* parent : exit */
4548
            exit(0);
4549
        } else {
4550
            /* child */
4551
            setsid();
4552
            chdir("/");
4553
            close(0);
4554
            open("/dev/null", O_RDWR);
4555
            if (strcmp(logfilename, "-") != 0) {
4556
                close(1);
4557
                dup(0);
4558
            }
4559
            close(2);
4560
            dup(0);
4561
        }
4562
    }
4563

    
4564
    /* signal init */
4565
    signal(SIGPIPE, SIG_IGN);
4566

    
4567
    /* open log file if needed */
4568
    if (logfilename[0] != '\0') {
4569
        if (!strcmp(logfilename, "-"))
4570
            logfile = stdout;
4571
        else
4572
            logfile = fopen(logfilename, "w");
4573
    }
4574

    
4575
    if (http_server() < 0) {
4576
        fprintf(stderr, "Could not start server\n");
4577
        exit(1);
4578
    }
4579

    
4580
    return 0;
4581
}