Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 9eb82647

History | View | Annotate | Download (132 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#define HAVE_AV_CONFIG_H
20
#include <netinet/in.h>
21
#include "avformat.h"
22

    
23
#include <stdarg.h>
24
#include <unistd.h>
25
#include <fcntl.h>
26
#include <sys/ioctl.h>
27
#include <sys/poll.h>
28
#include <errno.h>
29
#include <sys/time.h>
30
#include <time.h>
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/wait.h>
34
#ifndef __BEOS__
35
# include <arpa/inet.h>
36
#else
37
# include "libav/barpainet.h"
38
#endif
39
#include <netdb.h>
40
#include <ctype.h>
41
#include <signal.h>
42
#include <dlfcn.h>
43

    
44
#include "ffserver.h"
45

    
46
/* maximum number of simultaneous HTTP connections */
47
#define HTTP_MAX_CONNECTIONS 2000
48

    
49
enum HTTPState {
50
    HTTPSTATE_WAIT_REQUEST,
51
    HTTPSTATE_SEND_HEADER,
52
    HTTPSTATE_SEND_DATA_HEADER,
53
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
54
    HTTPSTATE_SEND_DATA_TRAILER,
55
    HTTPSTATE_RECEIVE_DATA,       
56
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
57
    HTTPSTATE_WAIT,               /* wait before sending next packets */
58
    HTTPSTATE_WAIT_SHORT,         /* short wait for short term 
59
                                     bandwidth limitation */
60
    HTTPSTATE_READY,
61

    
62
    RTSPSTATE_WAIT_REQUEST,
63
    RTSPSTATE_SEND_REPLY,
64
};
65

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

    
70
    "SEND_DATA_HEADER",
71
    "SEND_DATA",
72
    "SEND_DATA_TRAILER",
73
    "RECEIVE_DATA",
74
    "WAIT_FEED",
75
    "WAIT",
76
    "WAIT_SHORT",
77
    "READY",
78

    
79
    "RTSP_WAIT_REQUEST",
80
    "RTSP_SEND_REPLY",
81
};
82

    
83
#define IOBUFFER_INIT_SIZE 8192
84

    
85
/* coef for exponential mean for bitrate estimation in statistics */
86
#define AVG_COEF 0.9
87

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

    
92
#define SYNC_TIMEOUT (10 * 1000)
93

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

    
99
/* context associated with one connection */
100
typedef struct HTTPContext {
101
    enum HTTPState state;
102
    int fd; /* socket file descriptor */
103
    struct sockaddr_in from_addr; /* origin */
104
    struct pollfd *poll_entry; /* used when polling */
105
    long timeout;
106
    UINT8 *buffer_ptr, *buffer_end;
107
    int http_error;
108
    struct HTTPContext *next;
109
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
110
    INT64 data_count;
111
    /* feed input */
112
    int feed_fd;
113
    /* input format handling */
114
    AVFormatContext *fmt_in;
115
    long start_time;            /* In milliseconds - this wraps fairly often */
116
    INT64 first_pts;            /* initial pts value */
117
    int pts_stream_index;       /* stream we choose as clock reference */
118
    /* output format handling */
119
    struct FFStream *stream;
120
    /* -1 is invalid stream */
121
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
122
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
123
    int switch_pending;
124
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
125
    int last_packet_sent; /* true if last data packet was sent */
126
    int suppress_log;
127
    int bandwidth;
128
    DataRateData datarate;
129
    int wmp_client_id;
130
    char protocol[16];
131
    char method[16];
132
    char url[128];
133
    int buffer_size;
134
    UINT8 *buffer;
135
    int is_packetized; /* if true, the stream is packetized */
136
    int packet_stream_index; /* current stream for output in state machine */
137
    
138
    /* RTSP state specific */
139
    UINT8 *pb_buffer; /* XXX: use that in all the code */
140
    ByteIOContext *pb;
141
    int seq; /* RTSP sequence number */
142

    
143
    /* RTP state specific */
144
    enum RTSPProtocol rtp_protocol;
145
    char session_id[32]; /* session id */
146
    AVFormatContext *rtp_ctx[MAX_STREAMS];
147
    URLContext *rtp_handles[MAX_STREAMS];
148
    /* RTP short term bandwidth limitation */
149
    int packet_byte_count;
150
    int packet_start_time_us; /* used for short durations (a few
151
                                 seconds max) */
152
} HTTPContext;
153

    
154
/* each generated stream is described here */
155
enum StreamType {
156
    STREAM_TYPE_LIVE,
157
    STREAM_TYPE_STATUS,
158
    STREAM_TYPE_REDIRECT,
159
};
160

    
161
enum IPAddressAction {
162
    IP_ALLOW = 1,
163
    IP_DENY,
164
};
165

    
166
typedef struct IPAddressACL {
167
    struct IPAddressACL *next;
168
    enum IPAddressAction action;
169
    struct in_addr first;
170
    struct in_addr last;
171
} IPAddressACL;
172

    
173
/* description of each stream of the ffserver.conf file */
174
typedef struct FFStream {
175
    enum StreamType stream_type;
176
    char filename[1024];     /* stream filename */
177
    struct FFStream *feed;   /* feed we are using (can be null if
178
                                coming from file) */
179
    AVOutputFormat *fmt;
180
    IPAddressACL *acl;
181
    int nb_streams;
182
    int prebuffer;      /* Number of millseconds early to start */
183
    long max_time;      /* Number of milliseconds to run */
184
    int send_on_key;
185
    AVStream *streams[MAX_STREAMS];
186
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
187
    char feed_filename[1024]; /* file name of the feed storage, or
188
                                 input file name for a stream */
189
    char author[512];
190
    char title[512];
191
    char copyright[512];
192
    char comment[512];
193
    pid_t pid;  /* Of ffmpeg process */
194
    time_t pid_start;  /* Of ffmpeg process */
195
    char **child_argv;
196
    struct FFStream *next;
197
    /* RTSP options */
198
    char *rtsp_option;
199
    /* feed specific */
200
    int feed_opened;     /* true if someone is writing to the feed */
201
    int is_feed;         /* true if it is a feed */
202
    int conns_served;
203
    INT64 bytes_served;
204
    INT64 feed_max_size;      /* maximum storage size */
205
    INT64 feed_write_index;   /* current write position in feed (it wraps round) */
206
    INT64 feed_size;          /* current size of feed */
207
    struct FFStream *next_feed;
208
} FFStream;
209

    
210
typedef struct FeedData {
211
    long long data_count;
212
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
213
} FeedData;
214

    
215
struct sockaddr_in my_http_addr;
216
struct sockaddr_in my_rtsp_addr;
217

    
218
char logfilename[1024];
219
HTTPContext *first_http_ctx;
220
FFStream *first_feed;   /* contains only feeds */
221
FFStream *first_stream; /* contains all streams, including feeds */
222

    
223
static void new_connection(int server_fd, int is_rtsp);
224
static void close_connection(HTTPContext *c);
225

    
226
/* HTTP handling */
227
static int handle_connection(HTTPContext *c);
228
static int http_parse_request(HTTPContext *c);
229
static int http_send_data(HTTPContext *c);
230
static void compute_stats(HTTPContext *c);
231
static int open_input_stream(HTTPContext *c, const char *info);
232
static int http_start_receive_data(HTTPContext *c);
233
static int http_receive_data(HTTPContext *c);
234
static int compute_send_delay(HTTPContext *c);
235

    
236
/* RTSP handling */
237
static int rtsp_parse_request(HTTPContext *c);
238
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
239
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
240
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
241
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
242
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
243

    
244
/* RTP handling */
245
static HTTPContext *rtp_new_connection(HTTPContext *rtsp_c, 
246
                                       FFStream *stream, const char *session_id);
247
static int rtp_new_av_stream(HTTPContext *c, 
248
                             int stream_index, struct sockaddr_in *dest_addr);
249

    
250
static const char *my_program_name;
251
static const char *my_program_dir;
252

    
253
static int ffserver_debug;
254
static int ffserver_daemon;
255
static int no_launch;
256
static int need_to_start_children;
257

    
258
int nb_max_connections;
259
int nb_connections;
260

    
261
int nb_max_bandwidth;
262
int nb_bandwidth;
263

    
264
static long cur_time;           // Making this global saves on passing it around everywhere
265

    
266
static long gettime_ms(void)
267
{
268
    struct timeval tv;
269

    
270
    gettimeofday(&tv,NULL);
271
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
272
}
273

    
274
static FILE *logfile = NULL;
275

    
276
static void http_log(char *fmt, ...)
277
{
278
    va_list ap;
279
    va_start(ap, fmt);
280
    
281
    if (logfile) {
282
        vfprintf(logfile, fmt, ap);
283
        fflush(logfile);
284
    }
285
    va_end(ap);
286
}
287

    
288
static void log_connection(HTTPContext *c)
289
{
290
    char buf1[32], buf2[32], *p;
291
    time_t ti;
292

    
293
    if (c->suppress_log) 
294
        return;
295

    
296
    /* XXX: reentrant function ? */
297
    p = inet_ntoa(c->from_addr.sin_addr);
298
    strcpy(buf1, p);
299
    ti = time(NULL);
300
    p = ctime(&ti);
301
    strcpy(buf2, p);
302
    p = buf2 + strlen(p) - 1;
303
    if (*p == '\n')
304
        *p = '\0';
305
    http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
306
             buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
307
}
308

    
309
static void update_datarate(DataRateData *drd, INT64 count)
310
{
311
    if (!drd->time1 && !drd->count1) {
312
        drd->time1 = drd->time2 = cur_time;
313
        drd->count1 = drd->count2 = count;
314
    } else {
315
        if (cur_time - drd->time2 > 5000) {
316
            drd->time1 = drd->time2;
317
            drd->count1 = drd->count2;
318
            drd->time2 = cur_time;
319
            drd->count2 = count;
320
        }
321
    }
322
}
323

    
324
/* In bytes per second */
325
static int compute_datarate(DataRateData *drd, INT64 count)
326
{
327
    if (cur_time == drd->time1)
328
        return 0;
329

    
330
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
331
}
332

    
333
static int get_longterm_datarate(DataRateData *drd, INT64 count)
334
{
335
    /* You get the first 3 seconds flat out */
336
    if (cur_time - drd->time1 < 3000)
337
        return 0;
338

    
339
    return compute_datarate(drd, count);
340
}
341

    
342

    
343
static void start_children(FFStream *feed)
344
{
345
    if (no_launch)
346
        return;
347

    
348
    for (; feed; feed = feed->next) {
349
        if (feed->child_argv && !feed->pid) {
350
            feed->pid_start = time(0);
351

    
352
            feed->pid = fork();
353

    
354
            if (feed->pid < 0) {
355
                fprintf(stderr, "Unable to create children\n");
356
                exit(1);
357
            }
358
            if (!feed->pid) {
359
                /* In child */
360
                char pathname[1024];
361
                char *slash;
362
                int i;
363

    
364
                for (i = 3; i < 256; i++) {
365
                    close(i);
366
                }
367

    
368
                if (!ffserver_debug) {
369
                    i = open("/dev/null", O_RDWR);
370
                    if (i)
371
                        dup2(i, 0);
372
                    dup2(i, 1);
373
                    dup2(i, 2);
374
                    if (i)
375
                        close(i);
376
                }
377

    
378
                pstrcpy(pathname, sizeof(pathname), my_program_name);
379

    
380
                slash = strrchr(pathname, '/');
381
                if (!slash) {
382
                    slash = pathname;
383
                } else {
384
                    slash++;
385
                }
386
                strcpy(slash, "ffmpeg");
387

    
388
                /* This is needed to make relative pathnames work */
389
                chdir(my_program_dir);
390

    
391
                execvp(pathname, feed->child_argv);
392

    
393
                _exit(1);
394
            }
395
        }
396
    }
397
}
398

    
399
/* open a listening socket */
400
static int socket_open_listen(struct sockaddr_in *my_addr)
401
{
402
    int server_fd, tmp;
403

    
404
    server_fd = socket(AF_INET,SOCK_STREAM,0);
405
    if (server_fd < 0) {
406
        perror ("socket");
407
        return -1;
408
    }
409
        
410
    tmp = 1;
411
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
412

    
413
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
414
        perror ("bind");
415
        close(server_fd);
416
        return -1;
417
    }
418
  
419
    if (listen (server_fd, 5) < 0) {
420
        perror ("listen");
421
        close(server_fd);
422
        return -1;
423
    }
424
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
425

    
426
    return server_fd;
427
}
428

    
429

    
430
/* main loop of the http server */
431
static int http_server(void)
432
{
433
    int server_fd, ret, rtsp_server_fd, delay, delay1;
434
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
435
    HTTPContext *c, *c_next;
436

    
437
    server_fd = socket_open_listen(&my_http_addr);
438
    if (server_fd < 0)
439
        return -1;
440

    
441
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
442
    if (rtsp_server_fd < 0)
443
        return -1;
444
    
445
    http_log("ffserver started.\n");
446

    
447
    start_children(first_feed);
448

    
449
    first_http_ctx = NULL;
450
    nb_connections = 0;
451
    first_http_ctx = NULL;
452
    for(;;) {
453
        poll_entry = poll_table;
454
        poll_entry->fd = server_fd;
455
        poll_entry->events = POLLIN;
456
        poll_entry++;
457

    
458
        poll_entry->fd = rtsp_server_fd;
459
        poll_entry->events = POLLIN;
460
        poll_entry++;
461

    
462
        /* wait for events on each HTTP handle */
463
        c = first_http_ctx;
464
        delay = 1000;
465
        while (c != NULL) {
466
            int fd;
467
            fd = c->fd;
468
            switch(c->state) {
469
            case HTTPSTATE_SEND_HEADER:
470
            case RTSPSTATE_SEND_REPLY:
471
                c->poll_entry = poll_entry;
472
                poll_entry->fd = fd;
473
                poll_entry->events = POLLOUT;
474
                poll_entry++;
475
                break;
476
            case HTTPSTATE_SEND_DATA_HEADER:
477
            case HTTPSTATE_SEND_DATA:
478
            case HTTPSTATE_SEND_DATA_TRAILER:
479
                if (!c->is_packetized) {
480
                    /* for TCP, we output as much as we can (may need to put a limit) */
481
                    c->poll_entry = poll_entry;
482
                    poll_entry->fd = fd;
483
                    poll_entry->events = POLLOUT;
484
                    poll_entry++;
485
                } else {
486
                    /* not strictly correct, but currently cannot add
487
                       more than one fd in poll entry */
488
                    delay = 0;
489
                }
490
                break;
491
            case HTTPSTATE_WAIT_REQUEST:
492
            case HTTPSTATE_RECEIVE_DATA:
493
            case HTTPSTATE_WAIT_FEED:
494
            case RTSPSTATE_WAIT_REQUEST:
495
                /* need to catch errors */
496
                c->poll_entry = poll_entry;
497
                poll_entry->fd = fd;
498
                poll_entry->events = POLLIN;/* Maybe this will work */
499
                poll_entry++;
500
                break;
501
            case HTTPSTATE_WAIT:
502
                c->poll_entry = NULL;
503
                delay1 = compute_send_delay(c);
504
                if (delay1 < delay)
505
                    delay = delay1;
506
                break;
507
            case HTTPSTATE_WAIT_SHORT:
508
                c->poll_entry = NULL;
509
                delay1 = 10; /* one tick wait XXX: 10 ms assumed */
510
                if (delay1 < delay)
511
                    delay = delay1;
512
                break;
513
            default:
514
                c->poll_entry = NULL;
515
                break;
516
            }
517
            c = c->next;
518
        }
519

    
520
        /* wait for an event on one connection. We poll at least every
521
           second to handle timeouts */
522
        do {
523
            ret = poll(poll_table, poll_entry - poll_table, delay);
524
        } while (ret == -1);
525
        
526
        cur_time = gettime_ms();
527

    
528
        if (need_to_start_children) {
529
            need_to_start_children = 0;
530
            start_children(first_feed);
531
        }
532

    
533
        /* now handle the events */
534
        for(c = first_http_ctx; c != NULL; c = c_next) {
535
            c_next = c->next;
536
            if (handle_connection(c) < 0) {
537
                /* close and free the connection */
538
                log_connection(c);
539
                close_connection(c);
540
            }
541
        }
542

    
543
        poll_entry = poll_table;
544
        /* new HTTP connection request ? */
545
        if (poll_entry->revents & POLLIN) {
546
            new_connection(server_fd, 0);
547
        }
548
        poll_entry++;
549
        /* new RTSP connection request ? */
550
        if (poll_entry->revents & POLLIN) {
551
            new_connection(rtsp_server_fd, 1);
552
        }
553
    }
554
}
555

    
556
/* start waiting for a new HTTP/RTSP request */
557
static void start_wait_request(HTTPContext *c, int is_rtsp)
558
{
559
    c->buffer_ptr = c->buffer;
560
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
561

    
562
    if (is_rtsp) {
563
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
564
        c->state = RTSPSTATE_WAIT_REQUEST;
565
    } else {
566
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
567
        c->state = HTTPSTATE_WAIT_REQUEST;
568
    }
569
}
570

    
571
static void new_connection(int server_fd, int is_rtsp)
572
{
573
    struct sockaddr_in from_addr;
574
    int fd, len;
575
    HTTPContext *c = NULL;
576

    
577
    len = sizeof(from_addr);
578
    fd = accept(server_fd, (struct sockaddr *)&from_addr, 
579
                &len);
580
    if (fd < 0)
581
        return;
582
    fcntl(fd, F_SETFL, O_NONBLOCK);
583

    
584
    /* XXX: should output a warning page when coming
585
       close to the connection limit */
586
    if (nb_connections >= nb_max_connections)
587
        goto fail;
588
    
589
    /* add a new connection */
590
    c = av_mallocz(sizeof(HTTPContext));
591
    if (!c)
592
        goto fail;
593
    
594
    c->next = first_http_ctx;
595
    first_http_ctx = c;
596
    c->fd = fd;
597
    c->poll_entry = NULL;
598
    c->from_addr = from_addr;
599
    c->buffer_size = IOBUFFER_INIT_SIZE;
600
    c->buffer = av_malloc(c->buffer_size);
601
    if (!c->buffer)
602
        goto fail;
603
    nb_connections++;
604
    
605
    start_wait_request(c, is_rtsp);
606

    
607
    return;
608

    
609
 fail:
610
    if (c) {
611
        av_free(c->buffer);
612
        av_free(c);
613
    }
614
    close(fd);
615
}
616

    
617
static void close_connection(HTTPContext *c)
618
{
619
    HTTPContext **cp, *c1;
620
    int i, nb_streams;
621
    AVFormatContext *ctx;
622
    URLContext *h;
623
    AVStream *st;
624

    
625
    /* remove connection from list */
626
    cp = &first_http_ctx;
627
    while ((*cp) != NULL) {
628
        c1 = *cp;
629
        if (c1 == c) {
630
            *cp = c->next;
631
        } else {
632
            cp = &c1->next;
633
        }
634
    }
635

    
636
    /* remove connection associated resources */
637
    if (c->fd >= 0)
638
        close(c->fd);
639
    if (c->fmt_in) {
640
        /* close each frame parser */
641
        for(i=0;i<c->fmt_in->nb_streams;i++) {
642
            st = c->fmt_in->streams[i];
643
            if (st->codec.codec) {
644
                avcodec_close(&st->codec);
645
            }
646
        }
647
        av_close_input_file(c->fmt_in);
648
    }
649

    
650
    /* free RTP output streams if any */
651
    nb_streams = 0;
652
    if (c->stream) 
653
        nb_streams = c->stream->nb_streams;
654
    
655
    for(i=0;i<nb_streams;i++) {
656
        ctx = c->rtp_ctx[i];
657
        if (ctx) {
658
            av_write_trailer(ctx);
659
            av_free(ctx);
660
        }
661
        h = c->rtp_handles[i];
662
        if (h) {
663
            url_close(h);
664
        }
665
    }
666

    
667
    nb_bandwidth -= c->bandwidth;
668
    av_freep(&c->pb_buffer);
669
    av_free(c->buffer);
670
    av_free(c);
671
    nb_connections--;
672
}
673

    
674
static int handle_connection(HTTPContext *c)
675
{
676
    int len, ret;
677
    
678
    switch(c->state) {
679
    case HTTPSTATE_WAIT_REQUEST:
680
    case RTSPSTATE_WAIT_REQUEST:
681
        /* timeout ? */
682
        if ((c->timeout - cur_time) < 0)
683
            return -1;
684
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
685
            return -1;
686

    
687
        /* no need to read if no events */
688
        if (!(c->poll_entry->revents & POLLIN))
689
            return 0;
690
        /* read the data */
691
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
692
        if (len < 0) {
693
            if (errno != EAGAIN && errno != EINTR)
694
                return -1;
695
        } else if (len == 0) {
696
            return -1;
697
        } else {
698
            /* search for end of request. XXX: not fully correct since garbage could come after the end */
699
            UINT8 *ptr;
700
            c->buffer_ptr += len;
701
            ptr = c->buffer_ptr;
702
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
703
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
704
                /* request found : parse it and reply */
705
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
706
                    ret = http_parse_request(c);
707
                } else {
708
                    ret = rtsp_parse_request(c);
709
                }
710
                if (ret < 0)
711
                    return -1;
712
            } else if (ptr >= c->buffer_end) {
713
                /* request too long: cannot do anything */
714
                return -1;
715
            }
716
        }
717
        break;
718

    
719
    case HTTPSTATE_SEND_HEADER:
720
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
721
            return -1;
722

    
723
        /* no need to write if no events */
724
        if (!(c->poll_entry->revents & POLLOUT))
725
            return 0;
726
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
727
        if (len < 0) {
728
            if (errno != EAGAIN && errno != EINTR) {
729
                /* error : close connection */
730
                av_freep(&c->pb_buffer);
731
                return -1;
732
            }
733
        } else {
734
            c->buffer_ptr += len;
735
            if (c->stream)
736
                c->stream->bytes_served += len;
737
            c->data_count += len;
738
            if (c->buffer_ptr >= c->buffer_end) {
739
                av_freep(&c->pb_buffer);
740
                /* if error, exit */
741
                if (c->http_error) {
742
                    return -1;
743
                }
744
                /* all the buffer was sent : synchronize to the incoming stream */
745
                c->state = HTTPSTATE_SEND_DATA_HEADER;
746
                c->buffer_ptr = c->buffer_end = c->buffer;
747
            }
748
        }
749
        break;
750

    
751
    case HTTPSTATE_SEND_DATA:
752
    case HTTPSTATE_SEND_DATA_HEADER:
753
    case HTTPSTATE_SEND_DATA_TRAILER:
754
        /* for packetized output, we consider we can always write (the
755
           input streams sets the speed). It may be better to verify
756
           that we do not rely too much on the kernel queues */
757
        if (!c->is_packetized) {
758
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
759
                return -1;
760
            
761
            /* no need to read if no events */
762
            if (!(c->poll_entry->revents & POLLOUT))
763
                return 0;
764
        }
765
        if (http_send_data(c) < 0)
766
            return -1;
767
        break;
768
    case HTTPSTATE_RECEIVE_DATA:
769
        /* no need to read if no events */
770
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
771
            return -1;
772
        if (!(c->poll_entry->revents & POLLIN))
773
            return 0;
774
        if (http_receive_data(c) < 0)
775
            return -1;
776
        break;
777
    case HTTPSTATE_WAIT_FEED:
778
        /* no need to read if no events */
779
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
780
            return -1;
781

    
782
        /* nothing to do, we'll be waken up by incoming feed packets */
783
        break;
784

    
785
    case HTTPSTATE_WAIT:
786
        /* if the delay expired, we can send new packets */
787
        if (compute_send_delay(c) <= 0)
788
            c->state = HTTPSTATE_SEND_DATA;
789
        break;
790
    case HTTPSTATE_WAIT_SHORT:
791
        /* just return back to send data */
792
        c->state = HTTPSTATE_SEND_DATA;
793
        break;
794

    
795
    case RTSPSTATE_SEND_REPLY:
796
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
797
            av_freep(&c->pb_buffer);
798
            return -1;
799
        }
800
        /* no need to write if no events */
801
        if (!(c->poll_entry->revents & POLLOUT))
802
            return 0;
803
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
804
        if (len < 0) {
805
            if (errno != EAGAIN && errno != EINTR) {
806
                /* error : close connection */
807
                av_freep(&c->pb_buffer);
808
                return -1;
809
            }
810
        } else {
811
            c->buffer_ptr += len;
812
            c->data_count += len;
813
            if (c->buffer_ptr >= c->buffer_end) {
814
                /* all the buffer was sent : wait for a new request */
815
                av_freep(&c->pb_buffer);
816
                start_wait_request(c, 1);
817
            }
818
        }
819
        break;
820
    case HTTPSTATE_READY:
821
        /* nothing to do */
822
        break;
823
    default:
824
        return -1;
825
    }
826
    return 0;
827
}
828

    
829
static int extract_rates(char *rates, int ratelen, const char *request)
830
{
831
    const char *p;
832

    
833
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
834
        if (strncasecmp(p, "Pragma:", 7) == 0) {
835
            const char *q = p + 7;
836

    
837
            while (*q && *q != '\n' && isspace(*q))
838
                q++;
839

    
840
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
841
                int stream_no;
842
                int rate_no;
843

    
844
                q += 20;
845

    
846
                memset(rates, 0xff, ratelen);
847

    
848
                while (1) {
849
                    while (*q && *q != '\n' && *q != ':')
850
                        q++;
851

    
852
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
853
                        break;
854
                    }
855
                    stream_no--;
856
                    if (stream_no < ratelen && stream_no >= 0) {
857
                        rates[stream_no] = rate_no;
858
                    }
859

    
860
                    while (*q && *q != '\n' && !isspace(*q))
861
                        q++;
862
                }
863

    
864
                return 1;
865
            }
866
        }
867
        p = strchr(p, '\n');
868
        if (!p)
869
            break;
870

    
871
        p++;
872
    }
873

    
874
    return 0;
875
}
876

    
877
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
878
{
879
    int i;
880
    int best_bitrate = 100000000;
881
    int best = -1;
882

    
883
    for (i = 0; i < feed->nb_streams; i++) {
884
        AVCodecContext *feed_codec = &feed->streams[i]->codec;
885

    
886
        if (feed_codec->codec_id != codec->codec_id ||
887
            feed_codec->sample_rate != codec->sample_rate ||
888
            feed_codec->width != codec->width ||
889
            feed_codec->height != codec->height) {
890
            continue;
891
        }
892

    
893
        /* Potential stream */
894

    
895
        /* We want the fastest stream less than bit_rate, or the slowest 
896
         * faster than bit_rate
897
         */
898

    
899
        if (feed_codec->bit_rate <= bit_rate) {
900
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
901
                best_bitrate = feed_codec->bit_rate;
902
                best = i;
903
            }
904
        } else {
905
            if (feed_codec->bit_rate < best_bitrate) {
906
                best_bitrate = feed_codec->bit_rate;
907
                best = i;
908
            }
909
        }
910
    }
911

    
912
    return best;
913
}
914

    
915
static int modify_current_stream(HTTPContext *c, char *rates)
916
{
917
    int i;
918
    FFStream *req = c->stream;
919
    int action_required = 0;
920

    
921
    for (i = 0; i < req->nb_streams; i++) {
922
        AVCodecContext *codec = &req->streams[i]->codec;
923

    
924
        switch(rates[i]) {
925
            case 0:
926
                c->switch_feed_streams[i] = req->feed_streams[i];
927
                break;
928
            case 1:
929
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
930
                break;
931
            case 2:
932
                /* Wants off or slow */
933
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
934
#ifdef WANTS_OFF
935
                /* This doesn't work well when it turns off the only stream! */
936
                c->switch_feed_streams[i] = -2;
937
                c->feed_streams[i] = -2;
938
#endif
939
                break;
940
        }
941

    
942
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
943
            action_required = 1;
944
    }
945

    
946
    return action_required;
947
}
948

    
949

    
950
static void do_switch_stream(HTTPContext *c, int i)
951
{
952
    if (c->switch_feed_streams[i] >= 0) {
953
#ifdef PHILIP        
954
        c->feed_streams[i] = c->switch_feed_streams[i];
955
#endif
956

    
957
        /* Now update the stream */
958
    }
959
    c->switch_feed_streams[i] = -1;
960
}
961

    
962
/* XXX: factorize in utils.c ? */
963
/* XXX: take care with different space meaning */
964
static void skip_spaces(const char **pp)
965
{
966
    const char *p;
967
    p = *pp;
968
    while (*p == ' ' || *p == '\t')
969
        p++;
970
    *pp = p;
971
}
972

    
973
static void get_word(char *buf, int buf_size, const char **pp)
974
{
975
    const char *p;
976
    char *q;
977

    
978
    p = *pp;
979
    skip_spaces(&p);
980
    q = buf;
981
    while (!isspace(*p) && *p != '\0') {
982
        if ((q - buf) < buf_size - 1)
983
            *q++ = *p;
984
        p++;
985
    }
986
    if (buf_size > 0)
987
        *q = '\0';
988
    *pp = p;
989
}
990

    
991
static int validate_acl(FFStream *stream, HTTPContext *c)
992
{
993
    enum IPAddressAction last_action = IP_DENY;
994
    IPAddressACL *acl;
995
    struct in_addr *src = &c->from_addr.sin_addr;
996

    
997
    for (acl = stream->acl; acl; acl = acl->next) {
998
        if (src->s_addr >= acl->first.s_addr && src->s_addr <= acl->last.s_addr) {
999
            return (acl->action == IP_ALLOW) ? 1 : 0;
1000
        }
1001
        last_action = acl->action;
1002
    }
1003

    
1004
    /* Nothing matched, so return not the last action */
1005
    return (last_action == IP_DENY) ? 1 : 0;
1006
}
1007

    
1008
/* parse http request and prepare header */
1009
static int http_parse_request(HTTPContext *c)
1010
{
1011
    char *p;
1012
    int post;
1013
    int doing_asx;
1014
    int doing_asf_redirector;
1015
    int doing_ram;
1016
    int doing_rtsp_redirector;
1017
    char cmd[32];
1018
    char info[1024], *filename;
1019
    char url[1024], *q;
1020
    char protocol[32];
1021
    char msg[1024];
1022
    const char *mime_type;
1023
    FFStream *stream;
1024
    int i;
1025
    char ratebuf[32];
1026
    char *useragent = 0;
1027

    
1028
    p = c->buffer;
1029
    get_word(cmd, sizeof(cmd), (const char **)&p);
1030
    pstrcpy(c->method, sizeof(c->method), cmd);
1031

    
1032
    if (!strcmp(cmd, "GET"))
1033
        post = 0;
1034
    else if (!strcmp(cmd, "POST"))
1035
        post = 1;
1036
    else
1037
        return -1;
1038

    
1039
    get_word(url, sizeof(url), (const char **)&p);
1040
    pstrcpy(c->url, sizeof(c->url), url);
1041

    
1042
    get_word(protocol, sizeof(protocol), (const char **)&p);
1043
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1044
        return -1;
1045

    
1046
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1047
    
1048
    /* find the filename and the optional info string in the request */
1049
    p = url;
1050
    if (*p == '/')
1051
        p++;
1052
    filename = p;
1053
    p = strchr(p, '?');
1054
    if (p) {
1055
        pstrcpy(info, sizeof(info), p);
1056
        *p = '\0';
1057
    } else {
1058
        info[0] = '\0';
1059
    }
1060

    
1061
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1062
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1063
            useragent = p + 11;
1064
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1065
                useragent++;
1066
            break;
1067
        }
1068
        p = strchr(p, '\n');
1069
        if (!p)
1070
            break;
1071

    
1072
        p++;
1073
    }
1074

    
1075
    if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
1076
        doing_asx = 1;
1077
        filename[strlen(filename)-1] = 'f';
1078
    } else {
1079
        doing_asx = 0;
1080
    }
1081

    
1082
    if (strlen(filename) > 4 && strcmp(".asf", filename + strlen(filename) - 4) == 0 &&
1083
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1084
        /* if this isn't WMP or lookalike, return the redirector file */
1085
        doing_asf_redirector = 1;
1086
    } else {
1087
        doing_asf_redirector = 0;
1088
    }
1089

    
1090
    if (strlen(filename) > 4 && 
1091
        (strcmp(".rpm", filename + strlen(filename) - 4) == 0 ||
1092
         strcmp(".ram", filename + strlen(filename) - 4) == 0)) {
1093
        doing_ram = 1;
1094
        strcpy(filename + strlen(filename)-2, "m");
1095
    } else {
1096
        doing_ram = 0;
1097
    }
1098

    
1099
    if (strlen(filename) > 5 && 
1100
        strcmp(".rtsp", filename + strlen(filename) - 5) == 0) {
1101
        char file1[1024];
1102
        char file2[1024];
1103
        char *p;
1104

    
1105
        doing_rtsp_redirector = 1;
1106
        /* compute filename by matching without the file extensions */
1107
        pstrcpy(file1, sizeof(file1), filename);
1108
        p = strrchr(file1, '.');
1109
        if (p)
1110
            *p = '\0';
1111
        for(stream = first_stream; stream != NULL; stream = stream->next) {
1112
            pstrcpy(file2, sizeof(file2), stream->filename);
1113
            p = strrchr(file2, '.');
1114
            if (p)
1115
                *p = '\0';
1116
            if (!strcmp(file1, file2)) {
1117
                pstrcpy(url, sizeof(url), stream->filename);
1118
                filename = url;
1119
                break;
1120
            }
1121
        }
1122
    } else {
1123
        doing_rtsp_redirector = 0;
1124
    }
1125

    
1126
    stream = first_stream;
1127
    while (stream != NULL) {
1128
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1129
            break;
1130
        stream = stream->next;
1131
    }
1132
    if (stream == NULL) {
1133
        sprintf(msg, "File '%s' not found", url);
1134
        goto send_error;
1135
    }
1136

    
1137
    c->stream = stream;
1138
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1139
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1140

    
1141
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1142
        c->http_error = 301;
1143
        q = c->buffer;
1144
        q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1145
        q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1146
        q += sprintf(q, "Content-type: text/html\r\n");
1147
        q += sprintf(q, "\r\n");
1148
        q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1149
        q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1150
        q += sprintf(q, "</body></html>\r\n");
1151

    
1152
        /* prepare output buffer */
1153
        c->buffer_ptr = c->buffer;
1154
        c->buffer_end = q;
1155
        c->state = HTTPSTATE_SEND_HEADER;
1156
        return 0;
1157
    }
1158

    
1159
    /* If this is WMP, get the rate information */
1160
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1161
        if (modify_current_stream(c, ratebuf)) {
1162
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1163
                if (c->switch_feed_streams[i] >= 0)
1164
                    do_switch_stream(c, i);
1165
            }
1166
        }
1167
    }
1168

    
1169
    if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1170
        /* See if we meet the bandwidth requirements */
1171
        for(i=0;i<stream->nb_streams;i++) {
1172
            AVStream *st = stream->streams[i];
1173
            switch(st->codec.codec_type) {
1174
            case CODEC_TYPE_AUDIO:
1175
                c->bandwidth += st->codec.bit_rate;
1176
                break;
1177
            case CODEC_TYPE_VIDEO:
1178
                c->bandwidth += st->codec.bit_rate;
1179
                break;
1180
            default:
1181
                av_abort();
1182
            }
1183
        }
1184
    }
1185

    
1186
    c->bandwidth /= 1000;
1187
    nb_bandwidth += c->bandwidth;
1188

    
1189
    if (post == 0 && nb_max_bandwidth < nb_bandwidth) {
1190
        c->http_error = 200;
1191
        q = c->buffer;
1192
        q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1193
        q += sprintf(q, "Content-type: text/html\r\n");
1194
        q += sprintf(q, "\r\n");
1195
        q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1196
        q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1197
        q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1198
            nb_bandwidth, nb_max_bandwidth);
1199
        q += sprintf(q, "</body></html>\r\n");
1200

    
1201
        /* prepare output buffer */
1202
        c->buffer_ptr = c->buffer;
1203
        c->buffer_end = q;
1204
        c->state = HTTPSTATE_SEND_HEADER;
1205
        return 0;
1206
    }
1207
    
1208
    if (doing_asx || doing_ram || doing_asf_redirector || 
1209
        doing_rtsp_redirector) {
1210
        char *hostinfo = 0;
1211
        
1212
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1213
            if (strncasecmp(p, "Host:", 5) == 0) {
1214
                hostinfo = p + 5;
1215
                break;
1216
            }
1217
            p = strchr(p, '\n');
1218
            if (!p)
1219
                break;
1220

    
1221
            p++;
1222
        }
1223

    
1224
        if (hostinfo) {
1225
            char *eoh;
1226
            char hostbuf[260];
1227

    
1228
            while (isspace(*hostinfo))
1229
                hostinfo++;
1230

    
1231
            eoh = strchr(hostinfo, '\n');
1232
            if (eoh) {
1233
                if (eoh[-1] == '\r')
1234
                    eoh--;
1235

    
1236
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1237
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1238
                    hostbuf[eoh - hostinfo] = 0;
1239

    
1240
                    c->http_error = 200;
1241
                    q = c->buffer;
1242
                    if (doing_asx) {
1243
                        q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
1244
                        q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1245
                        q += sprintf(q, "\r\n");
1246
                        q += sprintf(q, "<ASX Version=\"3\">\r\n");
1247
                        q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
1248
                        q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", 
1249
                                hostbuf, filename, info);
1250
                        q += sprintf(q, "</ASX>\r\n");
1251
                    } else if (doing_ram) {
1252
                        q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
1253
                        q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
1254
                        q += sprintf(q, "\r\n");
1255
                        q += sprintf(q, "# Autogenerated by ffserver\r\n");
1256
                        q += sprintf(q, "http://%s/%s%s\r\n", 
1257
                                hostbuf, filename, info);
1258
                    } else if (doing_asf_redirector) {
1259
                        q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
1260
                        q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1261
                        q += sprintf(q, "\r\n");
1262
                        q += sprintf(q, "[Reference]\r\n");
1263
                        q += sprintf(q, "Ref1=http://%s/%s%s\r\n", 
1264
                                hostbuf, filename, info);
1265
                    } else if (doing_rtsp_redirector) {
1266
                        char hostname[256], *p;
1267
                        /* extract only hostname */
1268
                        pstrcpy(hostname, sizeof(hostname), hostbuf);
1269
                        p = strrchr(hostname, ':');
1270
                        if (p)
1271
                            *p = '\0';
1272
                        q += sprintf(q, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1273
                        /* XXX: incorrect mime type ? */
1274
                        q += sprintf(q, "Content-type: application/x-rtsp\r\n");
1275
                        q += sprintf(q, "\r\n");
1276
                        q += sprintf(q, "rtsp://%s:%d/%s\r\n", 
1277
                                     hostname, ntohs(my_rtsp_addr.sin_port), 
1278
                                     filename);
1279
                    } else {
1280
                        av_abort();
1281
                    }
1282

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

    
1292
        sprintf(msg, "ASX/RAM file not handled");
1293
        goto send_error;
1294
    }
1295

    
1296
    stream->conns_served++;
1297

    
1298
    /* XXX: add there authenticate and IP match */
1299

    
1300
    if (post) {
1301
        /* if post, it means a feed is being sent */
1302
        if (!stream->is_feed) {
1303
            /* However it might be a status report from WMP! Lets log the data
1304
             * as it might come in handy one day
1305
             */
1306
            char *logline = 0;
1307
            int client_id = 0;
1308
            
1309
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1310
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1311
                    logline = p;
1312
                    break;
1313
                }
1314
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1315
                    client_id = strtol(p + 18, 0, 10);
1316
                }
1317
                p = strchr(p, '\n');
1318
                if (!p)
1319
                    break;
1320

    
1321
                p++;
1322
            }
1323

    
1324
            if (logline) {
1325
                char *eol = strchr(logline, '\n');
1326

    
1327
                logline += 17;
1328

    
1329
                if (eol) {
1330
                    if (eol[-1] == '\r')
1331
                        eol--;
1332
                    http_log("%.*s\n", eol - logline, logline);
1333
                    c->suppress_log = 1;
1334
                }
1335
            }
1336

    
1337
#ifdef DEBUG_WMP
1338
            http_log("\nGot request:\n%s\n", c->buffer);
1339
#endif
1340

    
1341
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1342
                HTTPContext *wmpc;
1343

    
1344
                /* Now we have to find the client_id */
1345
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1346
                    if (wmpc->wmp_client_id == client_id)
1347
                        break;
1348
                }
1349

    
1350
                if (wmpc) {
1351
                    if (modify_current_stream(wmpc, ratebuf)) {
1352
                        wmpc->switch_pending = 1;
1353
                    }
1354
                }
1355
            }
1356
            
1357
            sprintf(msg, "POST command not handled");
1358
            goto send_error;
1359
        }
1360
        if (http_start_receive_data(c) < 0) {
1361
            sprintf(msg, "could not open feed");
1362
            goto send_error;
1363
        }
1364
        c->http_error = 0;
1365
        c->state = HTTPSTATE_RECEIVE_DATA;
1366
        return 0;
1367
    }
1368

    
1369
#ifdef DEBUG_WMP
1370
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1371
        http_log("\nGot request:\n%s\n", c->buffer);
1372
    }
1373
#endif
1374

    
1375
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1376
        goto send_stats;
1377

    
1378
    /* open input stream */
1379
    if (open_input_stream(c, info) < 0) {
1380
        sprintf(msg, "Input stream corresponding to '%s' not found", url);
1381
        goto send_error;
1382
    }
1383

    
1384
    /* prepare http header */
1385
    q = c->buffer;
1386
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1387
    mime_type = c->stream->fmt->mime_type;
1388
    if (!mime_type)
1389
        mime_type = "application/x-octet_stream";
1390
    q += sprintf(q, "Pragma: no-cache\r\n");
1391

    
1392
    /* for asf, we need extra headers */
1393
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1394
        /* Need to allocate a client id */
1395

    
1396
        c->wmp_client_id = random() & 0x7fffffff;
1397

    
1398
        q += sprintf(q, "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);
1399
        mime_type = "application/octet-stream"; 
1400
    }
1401
    q += sprintf(q, "Content-Type: %s\r\n", mime_type);
1402
    q += sprintf(q, "\r\n");
1403
    
1404
    /* prepare output buffer */
1405
    c->http_error = 0;
1406
    c->buffer_ptr = c->buffer;
1407
    c->buffer_end = q;
1408
    c->state = HTTPSTATE_SEND_HEADER;
1409
    return 0;
1410
 send_error:
1411
    c->http_error = 404;
1412
    q = c->buffer;
1413
    q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1414
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
1415
    q += sprintf(q, "\r\n");
1416
    q += sprintf(q, "<HTML>\n");
1417
    q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1418
    q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1419
    q += sprintf(q, "</HTML>\n");
1420

    
1421
    /* prepare output buffer */
1422
    c->buffer_ptr = c->buffer;
1423
    c->buffer_end = q;
1424
    c->state = HTTPSTATE_SEND_HEADER;
1425
    return 0;
1426
 send_stats:
1427
    compute_stats(c);
1428
    c->http_error = 200; /* horrible : we use this value to avoid
1429
                            going to the send data state */
1430
    c->state = HTTPSTATE_SEND_HEADER;
1431
    return 0;
1432
}
1433

    
1434
static void fmt_bytecount(ByteIOContext *pb, INT64 count)
1435
{
1436
    static const char *suffix = " kMGTP";
1437
    const char *s;
1438

    
1439
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1440
    }
1441

    
1442
    url_fprintf(pb, "%lld%c", count, *s);
1443
}
1444

    
1445
static void compute_stats(HTTPContext *c)
1446
{
1447
    HTTPContext *c1;
1448
    FFStream *stream;
1449
    char *p;
1450
    time_t ti;
1451
    int i, len;
1452
    ByteIOContext pb1, *pb = &pb1;
1453

    
1454
    if (url_open_dyn_buf(pb) < 0) {
1455
        /* XXX: return an error ? */
1456
        c->buffer_ptr = c->buffer;
1457
        c->buffer_end = c->buffer;
1458
        return;
1459
    }
1460

    
1461
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1462
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1463
    url_fprintf(pb, "Pragma: no-cache\r\n");
1464
    url_fprintf(pb, "\r\n");
1465
    
1466
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1467
    if (c->stream->feed_filename) {
1468
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1469
    }
1470
    url_fprintf(pb, "</HEAD>\n<BODY>");
1471
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1472
    /* format status */
1473
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1474
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1475
    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");
1476
    stream = first_stream;
1477
    while (stream != NULL) {
1478
        char sfilename[1024];
1479
        char *eosf;
1480

    
1481
        if (stream->feed != stream) {
1482
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1483
            eosf = sfilename + strlen(sfilename);
1484
            if (eosf - sfilename >= 4) {
1485
                if (strcmp(eosf - 4, ".asf") == 0) {
1486
                    strcpy(eosf - 4, ".asx");
1487
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1488
                    strcpy(eosf - 3, ".ram");
1489
                } else if (stream->fmt == &rtp_mux) {
1490
                    /* generate a sample RTSP director - maybe should
1491
                       generate a .sdp file ? */
1492
                    eosf = strrchr(sfilename, '.');
1493
                    if (!eosf)
1494
                        eosf = sfilename + strlen(sfilename);
1495
                    strcpy(eosf, ".rtsp");
1496
                }
1497
            }
1498
            
1499
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
1500
                         sfilename, stream->filename);
1501
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1502
                        stream->conns_served);
1503
            fmt_bytecount(pb, stream->bytes_served);
1504
            switch(stream->stream_type) {
1505
            case STREAM_TYPE_LIVE:
1506
                {
1507
                    int audio_bit_rate = 0;
1508
                    int video_bit_rate = 0;
1509
                    char *audio_codec_name = "";
1510
                    char *video_codec_name = "";
1511
                    char *audio_codec_name_extra = "";
1512
                    char *video_codec_name_extra = "";
1513

    
1514
                    for(i=0;i<stream->nb_streams;i++) {
1515
                        AVStream *st = stream->streams[i];
1516
                        AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1517
                        switch(st->codec.codec_type) {
1518
                        case CODEC_TYPE_AUDIO:
1519
                            audio_bit_rate += st->codec.bit_rate;
1520
                            if (codec) {
1521
                                if (*audio_codec_name)
1522
                                    audio_codec_name_extra = "...";
1523
                                audio_codec_name = codec->name;
1524
                            }
1525
                            break;
1526
                        case CODEC_TYPE_VIDEO:
1527
                            video_bit_rate += st->codec.bit_rate;
1528
                            if (codec) {
1529
                                if (*video_codec_name)
1530
                                    video_codec_name_extra = "...";
1531
                                video_codec_name = codec->name;
1532
                            }
1533
                            break;
1534
                        default:
1535
                            av_abort();
1536
                        }
1537
                    }
1538
                    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", 
1539
                                 stream->fmt->name,
1540
                                 (audio_bit_rate + video_bit_rate) / 1000,
1541
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1542
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1543
                    if (stream->feed) {
1544
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1545
                    } else {
1546
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1547
                    }
1548
                    url_fprintf(pb, "\n");
1549
                }
1550
                break;
1551
            default:
1552
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1553
                break;
1554
            }
1555
        }
1556
        stream = stream->next;
1557
    }
1558
    url_fprintf(pb, "</TABLE>\n");
1559

    
1560
    stream = first_stream;
1561
    while (stream != NULL) {
1562
        if (stream->feed == stream) {
1563
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1564
            if (stream->pid) {
1565
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1566

    
1567
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1568
                {
1569
                    FILE *pid_stat;
1570
                    char ps_cmd[64];
1571

    
1572
                    /* This is somewhat linux specific I guess */
1573
                    snprintf(ps_cmd, sizeof(ps_cmd), 
1574
                             "ps -o \"%%cpu,cputime\" --no-headers %d", 
1575
                             stream->pid);
1576
                    
1577
                    pid_stat = popen(ps_cmd, "r");
1578
                    if (pid_stat) {
1579
                        char cpuperc[10];
1580
                        char cpuused[64];
1581
                        
1582
                        if (fscanf(pid_stat, "%10s %64s", cpuperc, 
1583
                                   cpuused) == 2) {
1584
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1585
                                         cpuperc, cpuused);
1586
                        }
1587
                        fclose(pid_stat);
1588
                    }
1589
                }
1590
#endif
1591

    
1592
                url_fprintf(pb, "<p>");
1593
            }
1594
            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");
1595

    
1596
            for (i = 0; i < stream->nb_streams; i++) {
1597
                AVStream *st = stream->streams[i];
1598
                AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1599
                char *type = "unknown";
1600
                char parameters[64];
1601

    
1602
                parameters[0] = 0;
1603

    
1604
                switch(st->codec.codec_type) {
1605
                case CODEC_TYPE_AUDIO:
1606
                    type = "audio";
1607
                    break;
1608
                case CODEC_TYPE_VIDEO:
1609
                    type = "video";
1610
                    sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
1611
                                st->codec.qmin, st->codec.qmax, st->codec.frame_rate / FRAME_RATE_BASE);
1612
                    break;
1613
                default:
1614
                    av_abort();
1615
                }
1616
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1617
                        i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
1618
            }
1619
            url_fprintf(pb, "</table>\n");
1620

    
1621
        }       
1622
        stream = stream->next;
1623
    }
1624
    
1625
#if 0
1626
    {
1627
        float avg;
1628
        AVCodecContext *enc;
1629
        char buf[1024];
1630
        
1631
        /* feed status */
1632
        stream = first_feed;
1633
        while (stream != NULL) {
1634
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1635
            url_fprintf(pb, "<TABLE>\n");
1636
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1637
            for(i=0;i<stream->nb_streams;i++) {
1638
                AVStream *st = stream->streams[i];
1639
                FeedData *fdata = st->priv_data;
1640
                enc = &st->codec;
1641
            
1642
                avcodec_string(buf, sizeof(buf), enc);
1643
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1644
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1645
                    avg /= enc->frame_size;
1646
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
1647
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1648
            }
1649
            url_fprintf(pb, "</TABLE>\n");
1650
            stream = stream->next_feed;
1651
        }
1652
    }
1653
#endif
1654

    
1655
    /* connection status */
1656
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1657

    
1658
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1659
                 nb_connections, nb_max_connections);
1660

    
1661
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1662
                 nb_bandwidth, nb_max_bandwidth);
1663

    
1664
    url_fprintf(pb, "<TABLE>\n");
1665
    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");
1666
    c1 = first_http_ctx;
1667
    i = 0;
1668
    while (c1 != NULL) {
1669
        int bitrate;
1670
        int j;
1671

    
1672
        bitrate = 0;
1673
        if (c1->stream) {
1674
            for (j = 0; j < c1->stream->nb_streams; j++) {
1675
                if (!c1->stream->feed) {
1676
                    bitrate += c1->stream->streams[j]->codec.bit_rate;
1677
                } else {
1678
                    if (c1->feed_streams[j] >= 0) {
1679
                        bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
1680
                    }
1681
                }
1682
            }
1683
        }
1684

    
1685
        i++;
1686
        p = inet_ntoa(c1->from_addr.sin_addr);
1687
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>", 
1688
                    i, 
1689
                    c1->stream ? c1->stream->filename : "", 
1690
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1691
                    p, 
1692
                    c1->protocol,
1693
                    http_state[c1->state]);
1694
        fmt_bytecount(pb, bitrate);
1695
        url_fprintf(pb, "<td align=right>");
1696
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1697
        url_fprintf(pb, "<td align=right>");
1698
        fmt_bytecount(pb, c1->data_count);
1699
        url_fprintf(pb, "\n");
1700
        c1 = c1->next;
1701
    }
1702
    url_fprintf(pb, "</TABLE>\n");
1703
    
1704
    /* date */
1705
    ti = time(NULL);
1706
    p = ctime(&ti);
1707
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1708
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1709

    
1710
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1711
    c->buffer_ptr = c->pb_buffer;
1712
    c->buffer_end = c->pb_buffer + len;
1713
}
1714

    
1715
/* check if the parser needs to be opened for stream i */
1716
static void open_parser(AVFormatContext *s, int i)
1717
{
1718
    AVStream *st = s->streams[i];
1719
    AVCodec *codec;
1720

    
1721
    if (!st->codec.codec) {
1722
        codec = avcodec_find_decoder(st->codec.codec_id);
1723
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1724
            st->codec.parse_only = 1;
1725
            if (avcodec_open(&st->codec, codec) < 0) {
1726
                st->codec.parse_only = 0;
1727
            }
1728
        }
1729
    }
1730
}
1731

    
1732
static int open_input_stream(HTTPContext *c, const char *info)
1733
{
1734
    char buf[128];
1735
    char input_filename[1024];
1736
    AVFormatContext *s;
1737
    int buf_size, i;
1738
    INT64 stream_pos;
1739

    
1740
    /* find file name */
1741
    if (c->stream->feed) {
1742
        strcpy(input_filename, c->stream->feed->feed_filename);
1743
        buf_size = FFM_PACKET_SIZE;
1744
        /* compute position (absolute time) */
1745
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1746
            stream_pos = parse_date(buf, 0);
1747
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1748
            int prebuffer = strtol(buf, 0, 10);
1749
            stream_pos = av_gettime() - prebuffer * (INT64)1000000;
1750
        } else {
1751
            stream_pos = av_gettime() - c->stream->prebuffer * (INT64)1000;
1752
        }
1753
    } else {
1754
        strcpy(input_filename, c->stream->feed_filename);
1755
        buf_size = 0;
1756
        /* compute position (relative time) */
1757
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1758
            stream_pos = parse_date(buf, 1);
1759
        } else {
1760
            stream_pos = 0;
1761
        }
1762
    }
1763
    if (input_filename[0] == '\0')
1764
        return -1;
1765

    
1766
#if 0
1767
    { time_t when = stream_pos / 1000000;
1768
    http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1769
    }
1770
#endif
1771

    
1772
    /* open stream */
1773
    if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1774
        http_log("%s not found", input_filename);
1775
        return -1;
1776
    }
1777
    c->fmt_in = s;
1778
    
1779
    /* open each parser */
1780
    for(i=0;i<s->nb_streams;i++)
1781
        open_parser(s, i);
1782

    
1783
    /* choose stream as clock source (we favorize video stream if
1784
       present) for packet sending */
1785
    c->pts_stream_index = 0;
1786
    for(i=0;i<c->stream->nb_streams;i++) {
1787
        if (c->pts_stream_index == 0 && 
1788
            c->stream->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) {
1789
            c->pts_stream_index = i;
1790
        }
1791
    }
1792

    
1793
    if (c->fmt_in->iformat->read_seek) {
1794
        c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1795
    }
1796
    /* set the start time (needed for maxtime and RTP packet timing) */
1797
    c->start_time = cur_time;
1798
    c->first_pts = AV_NOPTS_VALUE;
1799
    return 0;
1800
}
1801

    
1802
/* currently desactivated because the new PTS handling is not
1803
   satisfactory yet */
1804
//#define AV_READ_FRAME
1805
#ifdef AV_READ_FRAME
1806

    
1807
/* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1808
   the return packet MUST NOT be freed */
1809
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1810
{
1811
    AVStream *st;
1812
    int len, ret, old_nb_streams, i;
1813

    
1814
    /* see if remaining frames must be parsed */
1815
    for(;;) {
1816
        if (s->cur_len > 0) {
1817
            st = s->streams[s->cur_pkt.stream_index];
1818
            len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size, 
1819
                                      s->cur_ptr, s->cur_len);
1820
            if (len < 0) {
1821
                /* error: get next packet */
1822
                s->cur_len = 0;
1823
            } else {
1824
                s->cur_ptr += len;
1825
                s->cur_len -= len;
1826
                if (pkt->size) {
1827
                    /* init pts counter if not done */
1828
                    if (st->pts.den == 0) {
1829
                        switch(st->codec.codec_type) {
1830
                        case CODEC_TYPE_AUDIO:
1831
                            st->pts_incr = (INT64)s->pts_den;
1832
                            av_frac_init(&st->pts, st->pts.val, 0, 
1833
                                         (INT64)s->pts_num * st->codec.sample_rate);
1834
                            break;
1835
                        case CODEC_TYPE_VIDEO:
1836
                            st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
1837
                            av_frac_init(&st->pts, st->pts.val, 0,
1838
                                         (INT64)s->pts_num * st->codec.frame_rate);
1839
                            break;
1840
                        default:
1841
                            av_abort();
1842
                        }
1843
                    }
1844
                    
1845
                    /* a frame was read: return it */
1846
                    pkt->pts = st->pts.val;
1847
#if 0
1848
                    printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
1849
                           st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
1850
#endif
1851
                    switch(st->codec.codec_type) {
1852
                    case CODEC_TYPE_AUDIO:
1853
                        av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
1854
                        break;
1855
                    case CODEC_TYPE_VIDEO:
1856
                        av_frac_add(&st->pts, st->pts_incr);
1857
                        break;
1858
                    default:
1859
                        av_abort();
1860
                    }
1861
                    pkt->stream_index = s->cur_pkt.stream_index;
1862
                    /* we use the codec indication because it is
1863
                       more accurate than the demux flags */
1864
                    pkt->flags = 0;
1865
                    if (st->codec.key_frame) 
1866
                        pkt->flags |= PKT_FLAG_KEY;
1867
                    return 0;
1868
                }
1869
            }
1870
        } else {
1871
            /* free previous packet */
1872
            av_free_packet(&s->cur_pkt); 
1873

    
1874
            old_nb_streams = s->nb_streams;
1875
            ret = av_read_packet(s, &s->cur_pkt);
1876
            if (ret)
1877
                return ret;
1878
            /* open parsers for each new streams */
1879
            for(i = old_nb_streams; i < s->nb_streams; i++)
1880
                open_parser(s, i);
1881
            st = s->streams[s->cur_pkt.stream_index];
1882

    
1883
            /* update current pts (XXX: dts handling) from packet, or
1884
               use current pts if none given */
1885
            if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
1886
                av_frac_set(&st->pts, s->cur_pkt.pts);
1887
            } else {
1888
                s->cur_pkt.pts = st->pts.val;
1889
            }
1890
            if (!st->codec.codec) {
1891
                /* no codec opened: just return the raw packet */
1892
                *pkt = s->cur_pkt;
1893

    
1894
                /* no codec opened: just update the pts by considering we
1895
                   have one frame and free the packet */
1896
                if (st->pts.den == 0) {
1897
                    switch(st->codec.codec_type) {
1898
                    case CODEC_TYPE_AUDIO:
1899
                        st->pts_incr = (INT64)s->pts_den * st->codec.frame_size;
1900
                        av_frac_init(&st->pts, st->pts.val, 0, 
1901
                                     (INT64)s->pts_num * st->codec.sample_rate);
1902
                        break;
1903
                    case CODEC_TYPE_VIDEO:
1904
                        st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
1905
                        av_frac_init(&st->pts, st->pts.val, 0,
1906
                                     (INT64)s->pts_num * st->codec.frame_rate);
1907
                        break;
1908
                    default:
1909
                        av_abort();
1910
                    }
1911
                }
1912
                av_frac_add(&st->pts, st->pts_incr);
1913
                return 0;
1914
            } else {
1915
                s->cur_ptr = s->cur_pkt.data;
1916
                s->cur_len = s->cur_pkt.size;
1917
            }
1918
        }
1919
    }
1920
}
1921

    
1922
static int compute_send_delay(HTTPContext *c)
1923
{
1924
    INT64 cur_pts, delta_pts, next_pts;
1925
    int delay1;
1926
    
1927
    /* compute current pts value from system time */
1928
    cur_pts = ((INT64)(cur_time - c->start_time) * c->fmt_in->pts_den) / 
1929
        (c->fmt_in->pts_num * 1000LL);
1930
    /* compute the delta from the stream we choose as
1931
       main clock (we do that to avoid using explicit
1932
       buffers to do exact packet reordering for each
1933
       stream */
1934
    /* XXX: really need to fix the number of streams */
1935
    if (c->pts_stream_index >= c->fmt_in->nb_streams)
1936
        next_pts = cur_pts;
1937
    else
1938
        next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
1939
    delta_pts = next_pts - cur_pts;
1940
    if (delta_pts <= 0) {
1941
        delay1 = 0;
1942
    } else {
1943
        delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
1944
    }
1945
    return delay1;
1946
}
1947
#else
1948

    
1949
/* just fall backs */
1950
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1951
{
1952
    return av_read_packet(s, pkt);
1953
}
1954

    
1955
static int compute_send_delay(HTTPContext *c)
1956
{
1957
    int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count); 
1958

    
1959
    if (datarate > c->bandwidth * 2000) {
1960
        return 1000;
1961
    }
1962
    return 0;
1963
}
1964

    
1965
#endif
1966
    
1967
static int http_prepare_data(HTTPContext *c)
1968
{
1969
    int i, len, ret;
1970
    AVFormatContext *ctx;
1971

    
1972
    switch(c->state) {
1973
    case HTTPSTATE_SEND_DATA_HEADER:
1974
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1975
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), 
1976
                c->stream->author);
1977
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), 
1978
                c->stream->comment);
1979
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), 
1980
                c->stream->copyright);
1981
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), 
1982
                c->stream->title);
1983

    
1984
        /* open output stream by using specified codecs */
1985
        c->fmt_ctx.oformat = c->stream->fmt;
1986
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
1987
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1988
            AVStream *st;
1989
            st = av_mallocz(sizeof(AVStream));
1990
            c->fmt_ctx.streams[i] = st;
1991
            /* if file or feed, then just take streams from FFStream struct */
1992
            if (!c->stream->feed || 
1993
                c->stream->feed == c->stream)
1994
                memcpy(st, c->stream->streams[i], sizeof(AVStream));
1995
            else
1996
                memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
1997
                           sizeof(AVStream));
1998
            st->codec.frame_number = 0; /* XXX: should be done in
1999
                                           AVStream, not in codec */
2000
        }
2001
        c->got_key_frame = 0;
2002

    
2003
        /* prepare header and save header data in a stream */
2004
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2005
            /* XXX: potential leak */
2006
            return -1;
2007
        }
2008
        c->fmt_ctx.pb.is_streamed = 1;
2009

    
2010
        av_write_header(&c->fmt_ctx);
2011

    
2012
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2013
        c->buffer_ptr = c->pb_buffer;
2014
        c->buffer_end = c->pb_buffer + len;
2015

    
2016
        c->state = HTTPSTATE_SEND_DATA;
2017
        c->last_packet_sent = 0;
2018
        break;
2019
    case HTTPSTATE_SEND_DATA:
2020
        /* find a new packet */
2021
        {
2022
            AVPacket pkt;
2023
            
2024
            /* read a packet from the input stream */
2025
            if (c->stream->feed) {
2026
                ffm_set_write_index(c->fmt_in, 
2027
                                    c->stream->feed->feed_write_index,
2028
                                    c->stream->feed->feed_size);
2029
            }
2030

    
2031
            if (c->stream->max_time && 
2032
                c->stream->max_time + c->start_time - cur_time < 0) {
2033
                /* We have timed out */
2034
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
2035
            } else {
2036
                if (1 || c->is_packetized) {
2037
                    if (compute_send_delay(c) > 0) {
2038
                        c->state = HTTPSTATE_WAIT;
2039
                        return 1; /* state changed */
2040
                    }
2041
                }
2042
                if (av_read_frame(c->fmt_in, &pkt) < 0) {
2043
                    if (c->stream->feed && c->stream->feed->feed_opened) {
2044
                        /* if coming from feed, it means we reached the end of the
2045
                           ffm file, so must wait for more data */
2046
                        c->state = HTTPSTATE_WAIT_FEED;
2047
                        return 1; /* state changed */
2048
                    } else {
2049
                        /* must send trailer now because eof or error */
2050
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2051
                    }
2052
                } else {
2053
                    /* update first pts if needed */
2054
                    if (c->first_pts == AV_NOPTS_VALUE)
2055
                        c->first_pts = pkt.pts;
2056
                    
2057
                    /* send it to the appropriate stream */
2058
                    if (c->stream->feed) {
2059
                        /* if coming from a feed, select the right stream */
2060
                        if (c->switch_pending) {
2061
                            c->switch_pending = 0;
2062
                            for(i=0;i<c->stream->nb_streams;i++) {
2063
                                if (c->switch_feed_streams[i] == pkt.stream_index) {
2064
                                    if (pkt.flags & PKT_FLAG_KEY) {
2065
                                        do_switch_stream(c, i);
2066
                                    }
2067
                                }
2068
                                if (c->switch_feed_streams[i] >= 0) {
2069
                                    c->switch_pending = 1;
2070
                                }
2071
                            }
2072
                        }
2073
                        for(i=0;i<c->stream->nb_streams;i++) {
2074
                            if (c->feed_streams[i] == pkt.stream_index) {
2075
                                pkt.stream_index = i;
2076
                                if (pkt.flags & PKT_FLAG_KEY) {
2077
                                    c->got_key_frame |= 1 << i;
2078
                                }
2079
                                /* See if we have all the key frames, then 
2080
                                 * we start to send. This logic is not quite
2081
                                 * right, but it works for the case of a 
2082
                                 * single video stream with one or more
2083
                                 * audio streams (for which every frame is 
2084
                                 * typically a key frame). 
2085
                                 */
2086
                                if (!c->stream->send_on_key || 
2087
                                    ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2088
                                    goto send_it;
2089
                                }
2090
                            }
2091
                        }
2092
                    } else {
2093
                        AVCodecContext *codec;
2094
                        
2095
                    send_it:
2096
                        /* specific handling for RTP: we use several
2097
                           output stream (one for each RTP
2098
                           connection). XXX: need more abstract handling */
2099
                        if (c->is_packetized) {
2100
                            c->packet_stream_index = pkt.stream_index;
2101
                            ctx = c->rtp_ctx[c->packet_stream_index];
2102
                            codec = &ctx->streams[0]->codec;
2103
                        } else {
2104
                            ctx = &c->fmt_ctx;
2105
                            /* Fudge here */
2106
                            codec = &ctx->streams[pkt.stream_index]->codec;
2107
                        }
2108
                        
2109
                        codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2110
                        
2111
#ifdef PJSG
2112
                        if (codec->codec_type == CODEC_TYPE_AUDIO) {
2113
                            codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2114
                            /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2115
                        }
2116
#endif
2117
                        
2118
                        if (c->is_packetized) {
2119
                            ret = url_open_dyn_packet_buf(&ctx->pb, 
2120
                                                          url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]));
2121
                            c->packet_byte_count = 0;
2122
                            c->packet_start_time_us = av_gettime();
2123
                        } else {
2124
                            ret = url_open_dyn_buf(&ctx->pb);
2125
                        }
2126
                        if (ret < 0) {
2127
                            /* XXX: potential leak */
2128
                            return -1;
2129
                        }
2130
                        if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2131
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2132
                        }
2133
                        
2134
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2135
                        c->buffer_ptr = c->pb_buffer;
2136
                        c->buffer_end = c->pb_buffer + len;
2137
                        
2138
                        codec->frame_number++;
2139
                    }
2140
#ifndef AV_READ_FRAME
2141
                    av_free_packet(&pkt);
2142
#endif
2143
                }
2144
            }
2145
        }
2146
        break;
2147
    default:
2148
    case HTTPSTATE_SEND_DATA_TRAILER:
2149
        /* last packet test ? */
2150
        if (c->last_packet_sent || c->is_packetized)
2151
            return -1;
2152
        ctx = &c->fmt_ctx;
2153
        /* prepare header */
2154
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2155
            /* XXX: potential leak */
2156
            return -1;
2157
        }
2158
        av_write_trailer(ctx);
2159
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2160
        c->buffer_ptr = c->pb_buffer;
2161
        c->buffer_end = c->pb_buffer + len;
2162

    
2163
        c->last_packet_sent = 1;
2164
        break;
2165
    }
2166
    return 0;
2167
}
2168

    
2169
/* in bit/s */
2170
#define SHORT_TERM_BANDWIDTH 8000000
2171

    
2172
/* should convert the format at the same time */
2173
static int http_send_data(HTTPContext *c)
2174
{
2175
    int len, ret, dt;
2176
    
2177
    while (c->buffer_ptr >= c->buffer_end) {
2178
        av_freep(&c->pb_buffer);
2179
        ret = http_prepare_data(c);
2180
        if (ret < 0)
2181
            return -1;
2182
        else if (ret == 0) {
2183
            continue;
2184
        } else {
2185
            /* state change requested */
2186
            return 0;
2187
        }
2188
    }
2189

    
2190
    if (c->buffer_ptr < c->buffer_end) {
2191
        if (c->is_packetized) {
2192
            /* RTP/UDP data output */
2193
            len = c->buffer_end - c->buffer_ptr;
2194
            if (len < 4) {
2195
                /* fail safe - should never happen */
2196
            fail1:
2197
                c->buffer_ptr = c->buffer_end;
2198
                return 0;
2199
            }
2200
            len = (c->buffer_ptr[0] << 24) |
2201
                (c->buffer_ptr[1] << 16) |
2202
                (c->buffer_ptr[2] << 8) |
2203
                (c->buffer_ptr[3]);
2204
            if (len > (c->buffer_end - c->buffer_ptr))
2205
                goto fail1;
2206
            
2207
            /* short term bandwidth limitation */
2208
            dt = av_gettime() - c->packet_start_time_us;
2209
            if (dt < 1)
2210
                dt = 1;
2211

    
2212
            if ((c->packet_byte_count + len) * (INT64)1000000 >= 
2213
                (SHORT_TERM_BANDWIDTH / 8) * (INT64)dt) {
2214
                /* bandwidth overflow : wait at most one tick and retry */
2215
                c->state = HTTPSTATE_WAIT_SHORT;
2216
                return 0;
2217
            }
2218

    
2219
            c->buffer_ptr += 4;
2220
            url_write(c->rtp_handles[c->packet_stream_index], 
2221
                      c->buffer_ptr, len);
2222
            c->buffer_ptr += len;
2223
            c->packet_byte_count += len;
2224
        } else {
2225
            /* TCP data output */
2226
            len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2227
            if (len < 0) {
2228
                if (errno != EAGAIN && errno != EINTR) {
2229
                    /* error : close connection */
2230
                    return -1;
2231
                } else {
2232
                    return 0;
2233
                }
2234
            } else {
2235
                c->buffer_ptr += len;
2236
            }
2237
        }
2238
        c->data_count += len;
2239
        update_datarate(&c->datarate, c->data_count);
2240
        if (c->stream)
2241
            c->stream->bytes_served += len;
2242
    }
2243
    return 0;
2244
}
2245

    
2246
static int http_start_receive_data(HTTPContext *c)
2247
{
2248
    int fd;
2249

    
2250
    if (c->stream->feed_opened)
2251
        return -1;
2252

    
2253
    /* open feed */
2254
    fd = open(c->stream->feed_filename, O_RDWR);
2255
    if (fd < 0)
2256
        return -1;
2257
    c->feed_fd = fd;
2258
    
2259
    c->stream->feed_write_index = ffm_read_write_index(fd);
2260
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2261
    lseek(fd, 0, SEEK_SET);
2262

    
2263
    /* init buffer input */
2264
    c->buffer_ptr = c->buffer;
2265
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2266
    c->stream->feed_opened = 1;
2267
    return 0;
2268
}
2269
    
2270
static int http_receive_data(HTTPContext *c)
2271
{
2272
    HTTPContext *c1;
2273

    
2274
    if (c->buffer_end > c->buffer_ptr) {
2275
        int len;
2276

    
2277
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2278
        if (len < 0) {
2279
            if (errno != EAGAIN && errno != EINTR) {
2280
                /* error : close connection */
2281
                goto fail;
2282
            }
2283
        } else if (len == 0) {
2284
            /* end of connection : close it */
2285
            goto fail;
2286
        } else {
2287
            c->buffer_ptr += len;
2288
            c->data_count += len;
2289
            update_datarate(&c->datarate, c->data_count);
2290
        }
2291
    }
2292

    
2293
    if (c->buffer_ptr >= c->buffer_end) {
2294
        FFStream *feed = c->stream;
2295
        /* a packet has been received : write it in the store, except
2296
           if header */
2297
        if (c->data_count > FFM_PACKET_SIZE) {
2298
            
2299
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2300
            /* XXX: use llseek or url_seek */
2301
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2302
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2303
            
2304
            feed->feed_write_index += FFM_PACKET_SIZE;
2305
            /* update file size */
2306
            if (feed->feed_write_index > c->stream->feed_size)
2307
                feed->feed_size = feed->feed_write_index;
2308

    
2309
            /* handle wrap around if max file size reached */
2310
            if (feed->feed_write_index >= c->stream->feed_max_size)
2311
                feed->feed_write_index = FFM_PACKET_SIZE;
2312

    
2313
            /* write index */
2314
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2315

    
2316
            /* wake up any waiting connections */
2317
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2318
                if (c1->state == HTTPSTATE_WAIT_FEED && 
2319
                    c1->stream->feed == c->stream->feed) {
2320
                    c1->state = HTTPSTATE_SEND_DATA;
2321
                }
2322
            }
2323
        } else {
2324
            /* We have a header in our hands that contains useful data */
2325
            AVFormatContext s;
2326
            AVInputFormat *fmt_in;
2327
            ByteIOContext *pb = &s.pb;
2328
            int i;
2329

    
2330
            memset(&s, 0, sizeof(s));
2331

    
2332
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2333
            pb->buf_end = c->buffer_end;        /* ?? */
2334
            pb->is_streamed = 1;
2335

    
2336
            /* use feed output format name to find corresponding input format */
2337
            fmt_in = av_find_input_format(feed->fmt->name);
2338
            if (!fmt_in)
2339
                goto fail;
2340

    
2341
            s.priv_data = av_mallocz(fmt_in->priv_data_size);
2342
            if (!s.priv_data)
2343
                goto fail;
2344

    
2345
            if (fmt_in->read_header(&s, 0) < 0) {
2346
                av_freep(&s.priv_data);
2347
                goto fail;
2348
            }
2349

    
2350
            /* Now we have the actual streams */
2351
            if (s.nb_streams != feed->nb_streams) {
2352
                av_freep(&s.priv_data);
2353
                goto fail;
2354
            }
2355
            for (i = 0; i < s.nb_streams; i++) {
2356
                memcpy(&feed->streams[i]->codec, 
2357
                       &s.streams[i]->codec, sizeof(AVCodecContext));
2358
            } 
2359
            av_freep(&s.priv_data);
2360
        }
2361
        c->buffer_ptr = c->buffer;
2362
    }
2363

    
2364
    return 0;
2365
 fail:
2366
    c->stream->feed_opened = 0;
2367
    close(c->feed_fd);
2368
    return -1;
2369
}
2370

    
2371
/********************************************************************/
2372
/* RTSP handling */
2373

    
2374
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2375
{
2376
    const char *str;
2377
    time_t ti;
2378
    char *p;
2379
    char buf2[32];
2380

    
2381
    switch(error_number) {
2382
#define DEF(n, c, s) case c: str = s; break; 
2383
#include "rtspcodes.h"
2384
#undef DEF
2385
    default:
2386
        str = "Unknown Error";
2387
        break;
2388
    }
2389
     
2390
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2391
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2392

    
2393
    /* output GMT time */
2394
    ti = time(NULL);
2395
    p = ctime(&ti);
2396
    strcpy(buf2, p);
2397
    p = buf2 + strlen(p) - 1;
2398
    if (*p == '\n')
2399
        *p = '\0';
2400
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2401
}
2402

    
2403
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2404
{
2405
    rtsp_reply_header(c, error_number);
2406
    url_fprintf(c->pb, "\r\n");
2407
}
2408

    
2409
static int rtsp_parse_request(HTTPContext *c)
2410
{
2411
    const char *p, *p1, *p2;
2412
    char cmd[32];
2413
    char url[1024];
2414
    char protocol[32];
2415
    char line[1024];
2416
    ByteIOContext pb1;
2417
    int len;
2418
    RTSPHeader header1, *header = &header1;
2419
    
2420
    c->buffer_ptr[0] = '\0';
2421
    p = c->buffer;
2422
    
2423
    get_word(cmd, sizeof(cmd), &p);
2424
    get_word(url, sizeof(url), &p);
2425
    get_word(protocol, sizeof(protocol), &p);
2426

    
2427
    pstrcpy(c->method, sizeof(c->method), cmd);
2428
    pstrcpy(c->url, sizeof(c->url), url);
2429
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2430

    
2431
    c->pb = &pb1;
2432
    if (url_open_dyn_buf(c->pb) < 0) {
2433
        /* XXX: cannot do more */
2434
        c->pb = NULL; /* safety */
2435
        return -1;
2436
    }
2437

    
2438
    /* check version name */
2439
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2440
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2441
        goto the_end;
2442
    }
2443

    
2444
    /* parse each header line */
2445
    memset(header, 0, sizeof(RTSPHeader));
2446
    /* skip to next line */
2447
    while (*p != '\n' && *p != '\0')
2448
        p++;
2449
    if (*p == '\n')
2450
        p++;
2451
    while (*p != '\0') {
2452
        p1 = strchr(p, '\n');
2453
        if (!p1)
2454
            break;
2455
        p2 = p1;
2456
        if (p2 > p && p2[-1] == '\r')
2457
            p2--;
2458
        /* skip empty line */
2459
        if (p2 == p)
2460
            break;
2461
        len = p2 - p;
2462
        if (len > sizeof(line) - 1)
2463
            len = sizeof(line) - 1;
2464
        memcpy(line, p, len);
2465
        line[len] = '\0';
2466
        rtsp_parse_line(header, line);
2467
        p = p1 + 1;
2468
    }
2469

    
2470
    /* handle sequence number */
2471
    c->seq = header->seq;
2472

    
2473
    if (!strcmp(cmd, "DESCRIBE")) {
2474
        rtsp_cmd_describe(c, url);
2475
    } else if (!strcmp(cmd, "SETUP")) {
2476
        rtsp_cmd_setup(c, url, header);
2477
    } else if (!strcmp(cmd, "PLAY")) {
2478
        rtsp_cmd_play(c, url, header);
2479
    } else if (!strcmp(cmd, "PAUSE")) {
2480
        rtsp_cmd_pause(c, url, header);
2481
    } else if (!strcmp(cmd, "TEARDOWN")) {
2482
        rtsp_cmd_teardown(c, url, header);
2483
    } else {
2484
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2485
    }
2486
 the_end:
2487
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2488
    c->pb = NULL; /* safety */
2489
    if (len < 0) {
2490
        /* XXX: cannot do more */
2491
        return -1;
2492
    }
2493
    c->buffer_ptr = c->pb_buffer;
2494
    c->buffer_end = c->pb_buffer + len;
2495
    c->state = RTSPSTATE_SEND_REPLY;
2496
    return 0;
2497
}
2498

    
2499
static int prepare_sdp_description(HTTPContext *c, 
2500
                                   FFStream *stream, UINT8 **pbuffer)
2501
{
2502
    ByteIOContext pb1, *pb = &pb1;
2503
    struct sockaddr_in my_addr;
2504
    int len, i, payload_type;
2505
    const char *ipstr, *title, *mediatype;
2506
    AVStream *st;
2507
    
2508
    len = sizeof(my_addr);
2509
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2510
    ipstr = inet_ntoa(my_addr.sin_addr);
2511

    
2512
    if (url_open_dyn_buf(pb) < 0)
2513
        return -1;
2514
    
2515
    /* general media info */
2516

    
2517
    url_fprintf(pb, "v=0\n");
2518
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2519
    title = stream->title;
2520
    if (title[0] == '\0')
2521
        title = "No Title";
2522
    url_fprintf(pb, "s=%s\n", title);
2523
    if (stream->comment[0] != '\0')
2524
        url_fprintf(pb, "i=%s\n", stream->comment);
2525
    
2526
    /* for each stream, we output the necessary info */
2527
    for(i = 0; i < stream->nb_streams; i++) {
2528
        st = stream->streams[i];
2529
        switch(st->codec.codec_type) {
2530
        case CODEC_TYPE_AUDIO:
2531
            mediatype = "audio";
2532
            break;
2533
        case CODEC_TYPE_VIDEO:
2534
            mediatype = "video";
2535
            break;
2536
        default:
2537
            mediatype = "application";
2538
            break;
2539
        }
2540
        /* XXX: the port indication is not correct (but should be correct
2541
           for broadcast) */
2542
        payload_type = rtp_get_payload_type(&st->codec);
2543

    
2544
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2545
                    mediatype, 0, payload_type);
2546
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2547
    }
2548
    return url_close_dyn_buf(pb, pbuffer);
2549
}
2550

    
2551
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2552
{
2553
    FFStream *stream;
2554
    char path1[1024];
2555
    const char *path;
2556
    UINT8 *content;
2557
    int content_length;
2558
    
2559
    /* find which url is asked */
2560
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2561
    path = path1;
2562
    if (*path == '/')
2563
        path++;
2564

    
2565
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2566
        if (!stream->is_feed && stream->fmt == &rtp_mux &&
2567
            !strcmp(path, stream->filename)) {
2568
            goto found;
2569
        }
2570
    }
2571
    /* no stream found */
2572
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2573
    return;
2574

    
2575
 found:
2576
    /* prepare the media description in sdp format */
2577
    content_length = prepare_sdp_description(c, stream, &content);
2578
    if (content_length < 0) {
2579
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2580
        return;
2581
    }
2582
    rtsp_reply_header(c, RTSP_STATUS_OK);
2583
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2584
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2585
    url_fprintf(c->pb, "\r\n");
2586
    put_buffer(c->pb, content, content_length);
2587
}
2588

    
2589
static HTTPContext *find_rtp_session(const char *session_id)
2590
{
2591
    HTTPContext *c;
2592

    
2593
    if (session_id[0] == '\0')
2594
        return NULL;
2595

    
2596
    for(c = first_http_ctx; c != NULL; c = c->next) {
2597
        if (!strcmp(c->session_id, session_id))
2598
            return c;
2599
    }
2600
    return NULL;
2601
}
2602

    
2603
RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2604
{
2605
    RTSPTransportField *th;
2606
    int i;
2607

    
2608
    for(i=0;i<h->nb_transports;i++) {
2609
        th = &h->transports[i];
2610
        if (th->protocol == protocol)
2611
            return th;
2612
    }
2613
    return NULL;
2614
}
2615

    
2616
static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2617
                           RTSPHeader *h)
2618
{
2619
    FFStream *stream;
2620
    int stream_index, port;
2621
    char buf[1024];
2622
    char path1[1024];
2623
    const char *path;
2624
    HTTPContext *rtp_c;
2625
    RTSPTransportField *th;
2626
    struct sockaddr_in dest_addr;
2627
    RTSPActionServerSetup setup;
2628
    
2629
    /* find which url is asked */
2630
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2631
    path = path1;
2632
    if (*path == '/')
2633
        path++;
2634

    
2635
    /* now check each stream */
2636
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2637
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2638
            /* accept aggregate filenames only if single stream */
2639
            if (!strcmp(path, stream->filename)) {
2640
                if (stream->nb_streams != 1) {
2641
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2642
                    return;
2643
                }
2644
                stream_index = 0;
2645
                goto found;
2646
            }
2647
                
2648
            for(stream_index = 0; stream_index < stream->nb_streams;
2649
                stream_index++) {
2650
                snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2651
                         stream->filename, stream_index);
2652
                if (!strcmp(path, buf))
2653
                    goto found;
2654
            }
2655
        }
2656
    }
2657
    /* no stream found */
2658
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2659
    return;
2660
 found:
2661

    
2662
    /* generate session id if needed */
2663
    if (h->session_id[0] == '\0') {
2664
        snprintf(h->session_id, sizeof(h->session_id), 
2665
                 "%08x%08x", (int)random(), (int)random());
2666
    }
2667

    
2668
    /* find rtp session, and create it if none found */
2669
    rtp_c = find_rtp_session(h->session_id);
2670
    if (!rtp_c) {
2671
        rtp_c = rtp_new_connection(c, stream, h->session_id);
2672
        if (!rtp_c) {
2673
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2674
            return;
2675
        }
2676

    
2677
        /* open input stream */
2678
        if (open_input_stream(rtp_c, "") < 0) {
2679
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2680
            return;
2681
        }
2682

    
2683
        /* always prefer UDP */
2684
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2685
        if (!th) {
2686
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2687
            if (!th) {
2688
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2689
                return;
2690
            }
2691
        }
2692
        rtp_c->rtp_protocol = th->protocol;
2693
    }
2694
    
2695
    /* test if stream is OK (test needed because several SETUP needs
2696
       to be done for a given file) */
2697
    if (rtp_c->stream != stream) {
2698
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2699
        return;
2700
    }
2701
    
2702
    /* test if stream is already set up */
2703
    if (rtp_c->rtp_ctx[stream_index]) {
2704
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2705
        return;
2706
    }
2707

    
2708
    /* check transport */
2709
    th = find_transport(h, rtp_c->rtp_protocol);
2710
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
2711
                th->client_port_min <= 0)) {
2712
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2713
        return;
2714
    }
2715

    
2716
    /* setup default options */
2717
    setup.transport_option[0] = '\0';
2718
    dest_addr = rtp_c->from_addr;
2719
    dest_addr.sin_port = htons(th->client_port_min);
2720
    
2721
    /* add transport option if needed */
2722
    if (ff_rtsp_callback) {
2723
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2724
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2725
                             (char *)&setup, sizeof(setup),
2726
                             stream->rtsp_option) < 0) {
2727
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2728
            return;
2729
        }
2730
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2731
    }
2732
    
2733
    /* setup stream */
2734
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2735
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2736
        return;
2737
    }
2738

    
2739
    /* now everything is OK, so we can send the connection parameters */
2740
    rtsp_reply_header(c, RTSP_STATUS_OK);
2741
    /* session ID */
2742
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2743

    
2744
    switch(rtp_c->rtp_protocol) {
2745
    case RTSP_PROTOCOL_RTP_UDP:
2746
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2747
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2748
                    "client_port=%d-%d;server_port=%d-%d",
2749
                    th->client_port_min, th->client_port_min + 1,
2750
                    port, port + 1);
2751
        break;
2752
    case RTSP_PROTOCOL_RTP_TCP:
2753
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2754
                    stream_index * 2, stream_index * 2 + 1);
2755
        break;
2756
    default:
2757
        break;
2758
    }
2759
    if (setup.transport_option[0] != '\0') {
2760
        url_fprintf(c->pb, ";%s", setup.transport_option);
2761
    }
2762
    url_fprintf(c->pb, "\r\n");
2763
    
2764

    
2765
    url_fprintf(c->pb, "\r\n");
2766
}
2767

    
2768

    
2769
/* find an rtp connection by using the session ID. Check consistency
2770
   with filename */
2771
static HTTPContext *find_rtp_session_with_url(const char *url, 
2772
                                              const char *session_id)
2773
{
2774
    HTTPContext *rtp_c;
2775
    char path1[1024];
2776
    const char *path;
2777

    
2778
    rtp_c = find_rtp_session(session_id);
2779
    if (!rtp_c)
2780
        return NULL;
2781

    
2782
    /* find which url is asked */
2783
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2784
    path = path1;
2785
    if (*path == '/')
2786
        path++;
2787
    if (strcmp(path, rtp_c->stream->filename) != 0)
2788
        return NULL;
2789
    return rtp_c;
2790
}
2791

    
2792
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2793
{
2794
    HTTPContext *rtp_c;
2795

    
2796
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2797
    if (!rtp_c) {
2798
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2799
        return;
2800
    }
2801
    
2802
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2803
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2804
        rtp_c->state != HTTPSTATE_READY) {
2805
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2806
        return;
2807
    }
2808

    
2809
    rtp_c->state = HTTPSTATE_SEND_DATA;
2810
    
2811
    /* now everything is OK, so we can send the connection parameters */
2812
    rtsp_reply_header(c, RTSP_STATUS_OK);
2813
    /* session ID */
2814
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2815
    url_fprintf(c->pb, "\r\n");
2816
}
2817

    
2818
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2819
{
2820
    HTTPContext *rtp_c;
2821

    
2822
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2823
    if (!rtp_c) {
2824
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2825
        return;
2826
    }
2827
    
2828
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2829
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
2830
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2831
        return;
2832
    }
2833
    
2834
    rtp_c->state = HTTPSTATE_READY;
2835
    
2836
    /* now everything is OK, so we can send the connection parameters */
2837
    rtsp_reply_header(c, RTSP_STATUS_OK);
2838
    /* session ID */
2839
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2840
    url_fprintf(c->pb, "\r\n");
2841
}
2842

    
2843
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2844
{
2845
    HTTPContext *rtp_c;
2846

    
2847
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2848
    if (!rtp_c) {
2849
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2850
        return;
2851
    }
2852
    
2853
    /* abort the session */
2854
    close_connection(rtp_c);
2855

    
2856
    if (ff_rtsp_callback) {
2857
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
2858
                         NULL, 0,
2859
                         rtp_c->stream->rtsp_option);
2860
    }
2861

    
2862
    /* now everything is OK, so we can send the connection parameters */
2863
    rtsp_reply_header(c, RTSP_STATUS_OK);
2864
    /* session ID */
2865
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2866
    url_fprintf(c->pb, "\r\n");
2867
}
2868

    
2869

    
2870
/********************************************************************/
2871
/* RTP handling */
2872

    
2873
static HTTPContext *rtp_new_connection(HTTPContext *rtsp_c, 
2874
                                       FFStream *stream, const char *session_id)
2875
{
2876
    HTTPContext *c = NULL;
2877

    
2878
    /* XXX: should output a warning page when coming
2879
       close to the connection limit */
2880
    if (nb_connections >= nb_max_connections)
2881
        goto fail;
2882
    
2883
    /* add a new connection */
2884
    c = av_mallocz(sizeof(HTTPContext));
2885
    if (!c)
2886
        goto fail;
2887
    
2888
    c->fd = -1;
2889
    c->poll_entry = NULL;
2890
    c->from_addr = rtsp_c->from_addr;
2891
    c->buffer_size = IOBUFFER_INIT_SIZE;
2892
    c->buffer = av_malloc(c->buffer_size);
2893
    if (!c->buffer)
2894
        goto fail;
2895
    nb_connections++;
2896
    c->stream = stream;
2897
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
2898
    c->state = HTTPSTATE_READY;
2899
    c->is_packetized = 1;
2900
    /* protocol is shown in statistics */
2901
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
2902

    
2903
    c->next = first_http_ctx;
2904
    first_http_ctx = c;
2905
    return c;
2906
        
2907
 fail:
2908
    if (c) {
2909
        av_free(c->buffer);
2910
        av_free(c);
2911
    }
2912
    return NULL;
2913
}
2914

    
2915
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
2916
   command). if dest_addr is NULL, then TCP tunneling in RTSP is
2917
   used. */
2918
static int rtp_new_av_stream(HTTPContext *c, 
2919
                             int stream_index, struct sockaddr_in *dest_addr)
2920
{
2921
    AVFormatContext *ctx;
2922
    AVStream *st;
2923
    char *ipaddr;
2924
    URLContext *h;
2925
    UINT8 *dummy_buf;
2926

    
2927
    /* now we can open the relevant output stream */
2928
    ctx = av_mallocz(sizeof(AVFormatContext));
2929
    if (!ctx)
2930
        return -1;
2931
    ctx->oformat = &rtp_mux;
2932

    
2933
    st = av_mallocz(sizeof(AVStream));
2934
    if (!st)
2935
        goto fail;
2936
    ctx->nb_streams = 1;
2937
    ctx->streams[0] = st;
2938

    
2939
    if (!c->stream->feed || 
2940
        c->stream->feed == c->stream) {
2941
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
2942
    } else {
2943
        memcpy(st, 
2944
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
2945
               sizeof(AVStream));
2946
    }
2947
    
2948
    if (dest_addr) {
2949
        /* build destination RTP address */
2950
        ipaddr = inet_ntoa(dest_addr->sin_addr);
2951
        
2952
        snprintf(ctx->filename, sizeof(ctx->filename),
2953
                 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
2954
        
2955
        printf("open %s\n", ctx->filename);
2956

    
2957
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
2958
            goto fail;
2959
        c->rtp_handles[stream_index] = h;
2960
    } else {
2961
        goto fail;
2962
    }
2963

    
2964
    /* normally, no packets should be output here, but the packet size may be checked */
2965
    if (url_open_dyn_packet_buf(&ctx->pb, 
2966
                                url_get_max_packet_size(h)) < 0) {
2967
        /* XXX: close stream */
2968
        goto fail;
2969
    }
2970
    if (av_write_header(ctx) < 0) {
2971
    fail:
2972
        if (h)
2973
            url_close(h);
2974
        av_free(ctx);
2975
        return -1;
2976
    }
2977
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
2978
    av_free(dummy_buf);
2979
    
2980
    c->rtp_ctx[stream_index] = ctx;
2981
    return 0;
2982
}
2983

    
2984
/********************************************************************/
2985
/* ffserver initialization */
2986

    
2987
AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
2988
{
2989
    AVStream *fst;
2990

    
2991
    fst = av_mallocz(sizeof(AVStream));
2992
    if (!fst)
2993
        return NULL;
2994
    fst->priv_data = av_mallocz(sizeof(FeedData));
2995
    memcpy(&fst->codec, codec, sizeof(AVCodecContext));
2996
    stream->streams[stream->nb_streams++] = fst;
2997
    return fst;
2998
}
2999

    
3000
/* return the stream number in the feed */
3001
int add_av_stream(FFStream *feed,
3002
                  AVStream *st)
3003
{
3004
    AVStream *fst;
3005
    AVCodecContext *av, *av1;
3006
    int i;
3007

    
3008
    av = &st->codec;
3009
    for(i=0;i<feed->nb_streams;i++) {
3010
        st = feed->streams[i];
3011
        av1 = &st->codec;
3012
        if (av1->codec_id == av->codec_id &&
3013
            av1->codec_type == av->codec_type &&
3014
            av1->bit_rate == av->bit_rate) {
3015

    
3016
            switch(av->codec_type) {
3017
            case CODEC_TYPE_AUDIO:
3018
                if (av1->channels == av->channels &&
3019
                    av1->sample_rate == av->sample_rate)
3020
                    goto found;
3021
                break;
3022
            case CODEC_TYPE_VIDEO:
3023
                if (av1->width == av->width &&
3024
                    av1->height == av->height &&
3025
                    av1->frame_rate == av->frame_rate &&
3026
                    av1->gop_size == av->gop_size)
3027
                    goto found;
3028
                break;
3029
            default:
3030
                av_abort();
3031
            }
3032
        }
3033
    }
3034
    
3035
    fst = add_av_stream1(feed, av);
3036
    if (!fst)
3037
        return -1;
3038
    return feed->nb_streams - 1;
3039
 found:
3040
    return i;
3041
}
3042

    
3043
void remove_stream(FFStream *stream)
3044
{
3045
    FFStream **ps;
3046
    ps = &first_stream;
3047
    while (*ps != NULL) {
3048
        if (*ps == stream) {
3049
            *ps = (*ps)->next;
3050
        } else {
3051
            ps = &(*ps)->next;
3052
        }
3053
    }
3054
}
3055

    
3056
/* compute the needed AVStream for each file */
3057
void build_file_streams(void)
3058
{
3059
    FFStream *stream, *stream_next;
3060
    AVFormatContext *infile;
3061
    int i;
3062

    
3063
    /* gather all streams */
3064
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3065
        stream_next = stream->next;
3066
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3067
            !stream->feed) {
3068
            /* the stream comes from a file */
3069
            /* try to open the file */
3070
            /* open stream */
3071
            if (av_open_input_file(&infile, stream->feed_filename, 
3072
                                   NULL, 0, NULL) < 0) {
3073
                http_log("%s not found", stream->feed_filename);
3074
                /* remove stream (no need to spend more time on it) */
3075
            fail:
3076
                remove_stream(stream);
3077
            } else {
3078
                /* find all the AVStreams inside and reference them in
3079
                   'stream' */
3080
                if (av_find_stream_info(infile) < 0) {
3081
                    http_log("Could not find codec parameters from '%s'", 
3082
                             stream->feed_filename);
3083
                    av_close_input_file(infile);
3084
                    goto fail;
3085
                }
3086
                for(i=0;i<infile->nb_streams;i++) {
3087
                    add_av_stream1(stream, &infile->streams[i]->codec);
3088
                }
3089
                av_close_input_file(infile);
3090
            }
3091
        }
3092
    }
3093
}
3094

    
3095
/* compute the needed AVStream for each feed */
3096
void build_feed_streams(void)
3097
{
3098
    FFStream *stream, *feed;
3099
    int i;
3100

    
3101
    /* gather all streams */
3102
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3103
        feed = stream->feed;
3104
        if (feed) {
3105
            if (!stream->is_feed) {
3106
                /* we handle a stream coming from a feed */
3107
                for(i=0;i<stream->nb_streams;i++) {
3108
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3109
                }
3110
            }
3111
        }
3112
    }
3113

    
3114
    /* gather all streams */
3115
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3116
        feed = stream->feed;
3117
        if (feed) {
3118
            if (stream->is_feed) {
3119
                for(i=0;i<stream->nb_streams;i++) {
3120
                    stream->feed_streams[i] = i;
3121
                }
3122
            }
3123
        }
3124
    }
3125

    
3126
    /* create feed files if needed */
3127
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3128
        int fd;
3129

    
3130
        if (url_exist(feed->feed_filename)) {
3131
            /* See if it matches */
3132
            AVFormatContext *s;
3133
            int matches = 0;
3134

    
3135
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3136
                /* Now see if it matches */
3137
                if (s->nb_streams == feed->nb_streams) {
3138
                    matches = 1;
3139
                    for(i=0;i<s->nb_streams;i++) {
3140
                        AVStream *sf, *ss;
3141
                        sf = feed->streams[i];
3142
                        ss = s->streams[i];
3143

    
3144
                        if (sf->index != ss->index ||
3145
                            sf->id != ss->id) {
3146
                            printf("Index & Id do not match for stream %d\n", i);
3147
                            matches = 0;
3148
                        } else {
3149
                            AVCodecContext *ccf, *ccs;
3150

    
3151
                            ccf = &sf->codec;
3152
                            ccs = &ss->codec;
3153
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3154

    
3155
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3156
                                printf("Codecs do not match for stream %d\n", i);
3157
                                matches = 0;
3158
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3159
                                printf("Codec bitrates do not match for stream %d\n", i);
3160
                                matches = 0;
3161
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3162
                                if (CHECK_CODEC(frame_rate) ||
3163
                                    CHECK_CODEC(width) ||
3164
                                    CHECK_CODEC(height)) {
3165
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3166
                                    matches = 0;
3167
                                }
3168
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3169
                                if (CHECK_CODEC(sample_rate) ||
3170
                                    CHECK_CODEC(channels) ||
3171
                                    CHECK_CODEC(frame_size)) {
3172
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3173
                                    matches = 0;
3174
                                }
3175
                            } else {
3176
                                printf("Unknown codec type\n");
3177
                                matches = 0;
3178
                            }
3179
                        }
3180
                        if (!matches) {
3181
                            break;
3182
                        }
3183
                    }
3184
                } else {
3185
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3186
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3187
                }
3188

    
3189
                av_close_input_file(s);
3190
            } else {
3191
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3192
                        feed->feed_filename);
3193
            }
3194
            if (!matches)
3195
                unlink(feed->feed_filename);
3196
        }
3197
        if (!url_exist(feed->feed_filename)) {
3198
            AVFormatContext s1, *s = &s1;
3199

    
3200
            /* only write the header of the ffm file */
3201
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3202
                fprintf(stderr, "Could not open output feed file '%s'\n",
3203
                        feed->feed_filename);
3204
                exit(1);
3205
            }
3206
            s->oformat = feed->fmt;
3207
            s->nb_streams = feed->nb_streams;
3208
            for(i=0;i<s->nb_streams;i++) {
3209
                AVStream *st;
3210
                st = feed->streams[i];
3211
                s->streams[i] = st;
3212
            }
3213
            av_write_header(s);
3214
            /* XXX: need better api */
3215
            av_freep(&s->priv_data);
3216
            url_fclose(&s->pb);
3217
        }
3218
        /* get feed size and write index */
3219
        fd = open(feed->feed_filename, O_RDONLY);
3220
        if (fd < 0) {
3221
            fprintf(stderr, "Could not open output feed file '%s'\n",
3222
                    feed->feed_filename);
3223
            exit(1);
3224
        }
3225

    
3226
        feed->feed_write_index = ffm_read_write_index(fd);
3227
        feed->feed_size = lseek(fd, 0, SEEK_END);
3228
        /* ensure that we do not wrap before the end of file */
3229
        if (feed->feed_max_size < feed->feed_size)
3230
            feed->feed_max_size = feed->feed_size;
3231

    
3232
        close(fd);
3233
    }
3234
}
3235

    
3236
static void get_arg(char *buf, int buf_size, const char **pp)
3237
{
3238
    const char *p;
3239
    char *q;
3240
    int quote;
3241

    
3242
    p = *pp;
3243
    while (isspace(*p)) p++;
3244
    q = buf;
3245
    quote = 0;
3246
    if (*p == '\"' || *p == '\'')
3247
        quote = *p++;
3248
    for(;;) {
3249
        if (quote) {
3250
            if (*p == quote)
3251
                break;
3252
        } else {
3253
            if (isspace(*p))
3254
                break;
3255
        }
3256
        if (*p == '\0')
3257
            break;
3258
        if ((q - buf) < buf_size - 1)
3259
            *q++ = *p;
3260
        p++;
3261
    }
3262
    *q = '\0';
3263
    if (quote && *p == quote)
3264
        p++;
3265
    *pp = p;
3266
}
3267

    
3268
/* add a codec and set the default parameters */
3269
void add_codec(FFStream *stream, AVCodecContext *av)
3270
{
3271
    AVStream *st;
3272

    
3273
    /* compute default parameters */
3274
    switch(av->codec_type) {
3275
    case CODEC_TYPE_AUDIO:
3276
        if (av->bit_rate == 0)
3277
            av->bit_rate = 64000;
3278
        if (av->sample_rate == 0)
3279
            av->sample_rate = 22050;
3280
        if (av->channels == 0)
3281
            av->channels = 1;
3282
        break;
3283
    case CODEC_TYPE_VIDEO:
3284
        if (av->bit_rate == 0)
3285
            av->bit_rate = 64000;
3286
        if (av->frame_rate == 0)
3287
            av->frame_rate = 5 * FRAME_RATE_BASE;
3288
        if (av->width == 0 || av->height == 0) {
3289
            av->width = 160;
3290
            av->height = 128;
3291
        }
3292
        /* Bitrate tolerance is less for streaming */
3293
        if (av->bit_rate_tolerance == 0)
3294
            av->bit_rate_tolerance = av->bit_rate / 4;
3295
        if (av->qmin == 0)
3296
            av->qmin = 3;
3297
        if (av->qmax == 0)
3298
            av->qmax = 31;
3299
        if (av->max_qdiff == 0)
3300
            av->max_qdiff = 3;
3301
        av->qcompress = 0.5;
3302
        av->qblur = 0.5;
3303

    
3304
        if (!av->rc_eq)
3305
            av->rc_eq = "tex^qComp";
3306
        if (!av->i_quant_factor)
3307
            av->i_quant_factor = -0.8;
3308
        if (!av->b_quant_factor)
3309
            av->b_quant_factor = 1.25;
3310
        if (!av->b_quant_offset)
3311
            av->b_quant_offset = 1.25;
3312
        if (!av->rc_min_rate)
3313
            av->rc_min_rate = av->bit_rate / 2;
3314
        if (!av->rc_max_rate)
3315
            av->rc_max_rate = av->bit_rate * 2;
3316

    
3317
        break;
3318
    default:
3319
        av_abort();
3320
    }
3321

    
3322
    st = av_mallocz(sizeof(AVStream));
3323
    if (!st)
3324
        return;
3325
    stream->streams[stream->nb_streams++] = st;
3326
    memcpy(&st->codec, av, sizeof(AVCodecContext));
3327
}
3328

    
3329
int opt_audio_codec(const char *arg)
3330
{
3331
    AVCodec *p;
3332

    
3333
    p = first_avcodec;
3334
    while (p) {
3335
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3336
            break;
3337
        p = p->next;
3338
    }
3339
    if (p == NULL) {
3340
        return CODEC_ID_NONE;
3341
    }
3342

    
3343
    return p->id;
3344
}
3345

    
3346
int opt_video_codec(const char *arg)
3347
{
3348
    AVCodec *p;
3349

    
3350
    p = first_avcodec;
3351
    while (p) {
3352
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3353
            break;
3354
        p = p->next;
3355
    }
3356
    if (p == NULL) {
3357
        return CODEC_ID_NONE;
3358
    }
3359

    
3360
    return p->id;
3361
}
3362

    
3363
/* simplistic plugin support */
3364

    
3365
void load_module(const char *filename)
3366
{
3367
    void *dll;
3368
    void (*init_func)(void);
3369
    dll = dlopen(filename, RTLD_NOW);
3370
    if (!dll) {
3371
        fprintf(stderr, "Could not load module '%s' - %s\n",
3372
                filename, dlerror());
3373
        return;
3374
    }
3375
    
3376
    init_func = dlsym(dll, "ffserver_module_init");
3377
    if (!init_func) {
3378
        fprintf(stderr, 
3379
                "%s: init function 'ffserver_module_init()' not found\n",
3380
                filename);
3381
        dlclose(dll);
3382
    }
3383

    
3384
    init_func();
3385
}
3386

    
3387
int parse_ffconfig(const char *filename)
3388
{
3389
    FILE *f;
3390
    char line[1024];
3391
    char cmd[64];
3392
    char arg[1024];
3393
    const char *p;
3394
    int val, errors, line_num;
3395
    FFStream **last_stream, *stream, *redirect;
3396
    FFStream **last_feed, *feed;
3397
    AVCodecContext audio_enc, video_enc;
3398
    int audio_id, video_id;
3399

    
3400
    f = fopen(filename, "r");
3401
    if (!f) {
3402
        perror(filename);
3403
        return -1;
3404
    }
3405
    
3406
    errors = 0;
3407
    line_num = 0;
3408
    first_stream = NULL;
3409
    last_stream = &first_stream;
3410
    first_feed = NULL;
3411
    last_feed = &first_feed;
3412
    stream = NULL;
3413
    feed = NULL;
3414
    redirect = NULL;
3415
    audio_id = CODEC_ID_NONE;
3416
    video_id = CODEC_ID_NONE;
3417
    for(;;) {
3418
        if (fgets(line, sizeof(line), f) == NULL)
3419
            break;
3420
        line_num++;
3421
        p = line;
3422
        while (isspace(*p)) 
3423
            p++;
3424
        if (*p == '\0' || *p == '#')
3425
            continue;
3426

    
3427
        get_arg(cmd, sizeof(cmd), &p);
3428
        
3429
        if (!strcasecmp(cmd, "Port")) {
3430
            get_arg(arg, sizeof(arg), &p);
3431
            my_http_addr.sin_port = htons (atoi(arg));
3432
        } else if (!strcasecmp(cmd, "BindAddress")) {
3433
            get_arg(arg, sizeof(arg), &p);
3434
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3435
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3436
                        filename, line_num, arg);
3437
                errors++;
3438
            }
3439
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3440
            ffserver_daemon = 0;
3441
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3442
            get_arg(arg, sizeof(arg), &p);
3443
            my_rtsp_addr.sin_port = htons (atoi(arg));
3444
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3445
            get_arg(arg, sizeof(arg), &p);
3446
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3447
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3448
                        filename, line_num, arg);
3449
                errors++;
3450
            }
3451
        } else if (!strcasecmp(cmd, "MaxClients")) {
3452
            get_arg(arg, sizeof(arg), &p);
3453
            val = atoi(arg);
3454
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3455
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3456
                        filename, line_num, arg);
3457
                errors++;
3458
            } else {
3459
                nb_max_connections = val;
3460
            }
3461
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3462
            get_arg(arg, sizeof(arg), &p);
3463
            val = atoi(arg);
3464
            if (val < 10 || val > 100000) {
3465
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3466
                        filename, line_num, arg);
3467
                errors++;
3468
            } else {
3469
                nb_max_bandwidth = val;
3470
            }
3471
        } else if (!strcasecmp(cmd, "CustomLog")) {
3472
            get_arg(logfilename, sizeof(logfilename), &p);
3473
        } else if (!strcasecmp(cmd, "<Feed")) {
3474
            /*********************************************/
3475
            /* Feed related options */
3476
            char *q;
3477
            if (stream || feed) {
3478
                fprintf(stderr, "%s:%d: Already in a tag\n",
3479
                        filename, line_num);
3480
            } else {
3481
                feed = av_mallocz(sizeof(FFStream));
3482
                /* add in stream list */
3483
                *last_stream = feed;
3484
                last_stream = &feed->next;
3485
                /* add in feed list */
3486
                *last_feed = feed;
3487
                last_feed = &feed->next_feed;
3488
                
3489
                get_arg(feed->filename, sizeof(feed->filename), &p);
3490
                q = strrchr(feed->filename, '>');
3491
                if (*q)
3492
                    *q = '\0';
3493
                feed->fmt = guess_format("ffm", NULL, NULL);
3494
                /* defaut feed file */
3495
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3496
                         "/tmp/%s.ffm", feed->filename);
3497
                feed->feed_max_size = 5 * 1024 * 1024;
3498
                feed->is_feed = 1;
3499
                feed->feed = feed; /* self feeding :-) */
3500
            }
3501
        } else if (!strcasecmp(cmd, "Launch")) {
3502
            if (feed) {
3503
                int i;
3504

    
3505
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3506

    
3507
                feed->child_argv[0] = av_malloc(7);
3508
                strcpy(feed->child_argv[0], "ffmpeg");
3509

    
3510
                for (i = 1; i < 62; i++) {
3511
                    char argbuf[256];
3512

    
3513
                    get_arg(argbuf, sizeof(argbuf), &p);
3514
                    if (!argbuf[0])
3515
                        break;
3516

    
3517
                    feed->child_argv[i] = av_malloc(strlen(argbuf + 1));
3518
                    strcpy(feed->child_argv[i], argbuf);
3519
                }
3520

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

    
3523
                snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3524
                    ntohs(my_http_addr.sin_port), feed->filename);
3525
            }
3526
        } else if (!strcasecmp(cmd, "File")) {
3527
            if (feed) {
3528
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3529
            } else if (stream) {
3530
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3531
            }
3532
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3533
            if (feed) {
3534
                const char *p1;
3535
                double fsize;
3536

    
3537
                get_arg(arg, sizeof(arg), &p);
3538
                p1 = arg;
3539
                fsize = strtod(p1, (char **)&p1);
3540
                switch(toupper(*p1)) {
3541
                case 'K':
3542
                    fsize *= 1024;
3543
                    break;
3544
                case 'M':
3545
                    fsize *= 1024 * 1024;
3546
                    break;
3547
                case 'G':
3548
                    fsize *= 1024 * 1024 * 1024;
3549
                    break;
3550
                }
3551
                feed->feed_max_size = (INT64)fsize;
3552
            }
3553
        } else if (!strcasecmp(cmd, "</Feed>")) {
3554
            if (!feed) {
3555
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3556
                        filename, line_num);
3557
                errors++;
3558
#if 0
3559
            } else {
3560
                /* Make sure that we start out clean */
3561
                if (unlink(feed->feed_filename) < 0 
3562
                    && errno != ENOENT) {
3563
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3564
                        filename, line_num, feed->feed_filename, strerror(errno));
3565
                    errors++;
3566
                }
3567
#endif
3568
            }
3569
            feed = NULL;
3570
        } else if (!strcasecmp(cmd, "<Stream")) {
3571
            /*********************************************/
3572
            /* Stream related options */
3573
            char *q;
3574
            if (stream || feed) {
3575
                fprintf(stderr, "%s:%d: Already in a tag\n",
3576
                        filename, line_num);
3577
            } else {
3578
                stream = av_mallocz(sizeof(FFStream));
3579
                *last_stream = stream;
3580
                last_stream = &stream->next;
3581

    
3582
                get_arg(stream->filename, sizeof(stream->filename), &p);
3583
                q = strrchr(stream->filename, '>');
3584
                if (*q)
3585
                    *q = '\0';
3586
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3587
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3588
                memset(&video_enc, 0, sizeof(AVCodecContext));
3589
                audio_id = CODEC_ID_NONE;
3590
                video_id = CODEC_ID_NONE;
3591
                if (stream->fmt) {
3592
                    audio_id = stream->fmt->audio_codec;
3593
                    video_id = stream->fmt->video_codec;
3594
                }
3595
            }
3596
        } else if (!strcasecmp(cmd, "Feed")) {
3597
            get_arg(arg, sizeof(arg), &p);
3598
            if (stream) {
3599
                FFStream *sfeed;
3600
                
3601
                sfeed = first_feed;
3602
                while (sfeed != NULL) {
3603
                    if (!strcmp(sfeed->filename, arg))
3604
                        break;
3605
                    sfeed = sfeed->next_feed;
3606
                }
3607
                if (!sfeed) {
3608
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3609
                            filename, line_num, arg);
3610
                } else {
3611
                    stream->feed = sfeed;
3612
                }
3613
            }
3614
        } else if (!strcasecmp(cmd, "Format")) {
3615
            get_arg(arg, sizeof(arg), &p);
3616
            if (!strcmp(arg, "status")) {
3617
                stream->stream_type = STREAM_TYPE_STATUS;
3618
                stream->fmt = NULL;
3619
            } else {
3620
                stream->stream_type = STREAM_TYPE_LIVE;
3621
                /* jpeg cannot be used here, so use single frame jpeg */
3622
                if (!strcmp(arg, "jpeg"))
3623
                    strcpy(arg, "singlejpeg");
3624
                stream->fmt = guess_stream_format(arg, NULL, NULL);
3625
                if (!stream->fmt) {
3626
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
3627
                            filename, line_num, arg);
3628
                    errors++;
3629
                }
3630
            }
3631
            if (stream->fmt) {
3632
                audio_id = stream->fmt->audio_codec;
3633
                video_id = stream->fmt->video_codec;
3634
            }
3635
        } else if (!strcasecmp(cmd, "FaviconURL")) {
3636
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3637
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3638
            } else {
3639
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
3640
                            filename, line_num);
3641
                errors++;
3642
            }
3643
        } else if (!strcasecmp(cmd, "Author")) {
3644
            if (stream) {
3645
                get_arg(stream->author, sizeof(stream->author), &p);
3646
            }
3647
        } else if (!strcasecmp(cmd, "Comment")) {
3648
            if (stream) {
3649
                get_arg(stream->comment, sizeof(stream->comment), &p);
3650
            }
3651
        } else if (!strcasecmp(cmd, "Copyright")) {
3652
            if (stream) {
3653
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
3654
            }
3655
        } else if (!strcasecmp(cmd, "Title")) {
3656
            if (stream) {
3657
                get_arg(stream->title, sizeof(stream->title), &p);
3658
            }
3659
        } else if (!strcasecmp(cmd, "Preroll")) {
3660
            get_arg(arg, sizeof(arg), &p);
3661
            if (stream) {
3662
                stream->prebuffer = atof(arg) * 1000;
3663
            }
3664
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3665
            if (stream) {
3666
                stream->send_on_key = 1;
3667
            }
3668
        } else if (!strcasecmp(cmd, "AudioCodec")) {
3669
            get_arg(arg, sizeof(arg), &p);
3670
            audio_id = opt_audio_codec(arg);
3671
            if (audio_id == CODEC_ID_NONE) {
3672
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
3673
                        filename, line_num, arg);
3674
                errors++;
3675
            }
3676
        } else if (!strcasecmp(cmd, "VideoCodec")) {
3677
            get_arg(arg, sizeof(arg), &p);
3678
            video_id = opt_video_codec(arg);
3679
            if (video_id == CODEC_ID_NONE) {
3680
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
3681
                        filename, line_num, arg);
3682
                errors++;
3683
            }
3684
        } else if (!strcasecmp(cmd, "MaxTime")) {
3685
            get_arg(arg, sizeof(arg), &p);
3686
            if (stream) {
3687
                stream->max_time = atof(arg) * 1000;
3688
            }
3689
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
3690
            get_arg(arg, sizeof(arg), &p);
3691
            if (stream) {
3692
                audio_enc.bit_rate = atoi(arg) * 1000;
3693
            }
3694
        } else if (!strcasecmp(cmd, "AudioChannels")) {
3695
            get_arg(arg, sizeof(arg), &p);
3696
            if (stream) {
3697
                audio_enc.channels = atoi(arg);
3698
            }
3699
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
3700
            get_arg(arg, sizeof(arg), &p);
3701
            if (stream) {
3702
                audio_enc.sample_rate = atoi(arg);
3703
            }
3704
        } else if (!strcasecmp(cmd, "AudioQuality")) {
3705
            get_arg(arg, sizeof(arg), &p);
3706
            if (stream) {
3707
                audio_enc.quality = atof(arg) * 1000;
3708
            }
3709
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
3710
            if (stream) {
3711
                int minrate, maxrate;
3712

    
3713
                get_arg(arg, sizeof(arg), &p);
3714

    
3715
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
3716
                    video_enc.rc_min_rate = minrate * 1000;
3717
                    video_enc.rc_max_rate = maxrate * 1000;
3718
                } else {
3719
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
3720
                            filename, line_num, arg);
3721
                    errors++;
3722
                }
3723
            }
3724
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
3725
            if (stream) {
3726
                get_arg(arg, sizeof(arg), &p);
3727
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
3728
            }
3729
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
3730
            get_arg(arg, sizeof(arg), &p);
3731
            if (stream) {
3732
                video_enc.bit_rate = atoi(arg) * 1000;
3733
            }
3734
        } else if (!strcasecmp(cmd, "VideoSize")) {
3735
            get_arg(arg, sizeof(arg), &p);
3736
            if (stream) {
3737
                parse_image_size(&video_enc.width, &video_enc.height, arg);
3738
                if ((video_enc.width % 16) != 0 ||
3739
                    (video_enc.height % 16) != 0) {
3740
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
3741
                            filename, line_num);
3742
                    errors++;
3743
                }
3744
            }
3745
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
3746
            get_arg(arg, sizeof(arg), &p);
3747
            if (stream) {
3748
                video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
3749
            }
3750
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
3751
            get_arg(arg, sizeof(arg), &p);
3752
            if (stream) {
3753
                video_enc.gop_size = atoi(arg);
3754
            }
3755
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
3756
            if (stream) {
3757
                video_enc.gop_size = 1;
3758
            }
3759
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
3760
            if (stream) {
3761
                video_enc.flags |= CODEC_FLAG_HQ;
3762
            }
3763
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
3764
            get_arg(arg, sizeof(arg), &p);
3765
            if (stream) {
3766
                video_enc.max_qdiff = atoi(arg);
3767
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
3768
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
3769
                            filename, line_num);
3770
                    errors++;
3771
                }
3772
            }
3773
        } else if (!strcasecmp(cmd, "VideoQMax")) {
3774
            get_arg(arg, sizeof(arg), &p);
3775
            if (stream) {
3776
                video_enc.qmax = atoi(arg);
3777
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
3778
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
3779
                            filename, line_num);
3780
                    errors++;
3781
                }
3782
            }
3783
        } else if (!strcasecmp(cmd, "VideoQMin")) {
3784
            get_arg(arg, sizeof(arg), &p);
3785
            if (stream) {
3786
                video_enc.qmin = atoi(arg);
3787
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
3788
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
3789
                            filename, line_num);
3790
                    errors++;
3791
                }
3792
            }
3793
        } else if (!strcasecmp(cmd, "LumaElim")) {
3794
            get_arg(arg, sizeof(arg), &p);
3795
            if (stream) {
3796
                video_enc.luma_elim_threshold = atoi(arg);
3797
            }
3798
        } else if (!strcasecmp(cmd, "ChromaElim")) {
3799
            get_arg(arg, sizeof(arg), &p);
3800
            if (stream) {
3801
                video_enc.chroma_elim_threshold = atoi(arg);
3802
            }
3803
        } else if (!strcasecmp(cmd, "LumiMask")) {
3804
            get_arg(arg, sizeof(arg), &p);
3805
            if (stream) {
3806
                video_enc.lumi_masking = atof(arg);
3807
            }
3808
        } else if (!strcasecmp(cmd, "DarkMask")) {
3809
            get_arg(arg, sizeof(arg), &p);
3810
            if (stream) {
3811
                video_enc.dark_masking = atof(arg);
3812
            }
3813
        } else if (!strcasecmp(cmd, "NoVideo")) {
3814
            video_id = CODEC_ID_NONE;
3815
        } else if (!strcasecmp(cmd, "NoAudio")) {
3816
            audio_id = CODEC_ID_NONE;
3817
        } else if (!strcasecmp(cmd, "ACL")) {
3818
            IPAddressACL acl;
3819
            struct hostent *he;
3820

    
3821
            get_arg(arg, sizeof(arg), &p);
3822
            if (strcasecmp(arg, "allow") == 0) {
3823
                acl.action = IP_ALLOW;
3824
            } else if (strcasecmp(arg, "deny") == 0) {
3825
                acl.action = IP_DENY;
3826
            } else {
3827
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
3828
                        filename, line_num, arg);
3829
                errors++;
3830
            }
3831

    
3832
            get_arg(arg, sizeof(arg), &p);
3833

    
3834
            he = gethostbyname(arg);
3835
            if (!he) {
3836
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
3837
                        filename, line_num, arg);
3838
                errors++;
3839
            } else {
3840
                /* Only take the first */
3841
                acl.first = *(struct in_addr *) he->h_addr_list[0];
3842
                acl.last = acl.first;
3843
            }
3844

    
3845
            get_arg(arg, sizeof(arg), &p);
3846

    
3847
            if (arg[0]) {
3848
                he = gethostbyname(arg);
3849
                if (!he) {
3850
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
3851
                            filename, line_num, arg);
3852
                    errors++;
3853
                } else {
3854
                    /* Only take the first */
3855
                    acl.last = *(struct in_addr *) he->h_addr_list[0];
3856
                }
3857
            }
3858

    
3859
            if (!errors) {
3860
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
3861
                IPAddressACL **naclp = 0;
3862

    
3863
                *nacl = acl;
3864
                nacl->next = 0;
3865

    
3866
                if (stream) {
3867
                    naclp = &stream->acl;
3868
                } else if (feed) {
3869
                    naclp = &feed->acl;
3870
                } else {
3871
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
3872
                            filename, line_num);
3873
                    errors++;
3874
                }
3875

    
3876
                if (naclp) {
3877
                    while (*naclp)
3878
                        naclp = &(*naclp)->next;
3879

    
3880
                    *naclp = nacl;
3881
                }
3882
            }
3883
        } else if (!strcasecmp(cmd, "RTSPOption")) {
3884
            get_arg(arg, sizeof(arg), &p);
3885
            if (stream) {
3886
                av_freep(&stream->rtsp_option);
3887
                /* XXX: av_strdup ? */
3888
                stream->rtsp_option = av_malloc(strlen(arg) + 1);
3889
                if (stream->rtsp_option) {
3890
                    strcpy(stream->rtsp_option, arg);
3891
                }
3892
            }
3893
        } else if (!strcasecmp(cmd, "</Stream>")) {
3894
            if (!stream) {
3895
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
3896
                        filename, line_num);
3897
                errors++;
3898
            }
3899
            if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
3900
                if (audio_id != CODEC_ID_NONE) {
3901
                    audio_enc.codec_type = CODEC_TYPE_AUDIO;
3902
                    audio_enc.codec_id = audio_id;
3903
                    add_codec(stream, &audio_enc);
3904
                }
3905
                if (video_id != CODEC_ID_NONE) {
3906
                    video_enc.codec_type = CODEC_TYPE_VIDEO;
3907
                    video_enc.codec_id = video_id;
3908
                    add_codec(stream, &video_enc);
3909
                }
3910
            }
3911
            stream = NULL;
3912
        } else if (!strcasecmp(cmd, "<Redirect")) {
3913
            /*********************************************/
3914
            char *q;
3915
            if (stream || feed || redirect) {
3916
                fprintf(stderr, "%s:%d: Already in a tag\n",
3917
                        filename, line_num);
3918
                errors++;
3919
            } else {
3920
                redirect = av_mallocz(sizeof(FFStream));
3921
                *last_stream = redirect;
3922
                last_stream = &redirect->next;
3923

    
3924
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
3925
                q = strrchr(redirect->filename, '>');
3926
                if (*q)
3927
                    *q = '\0';
3928
                redirect->stream_type = STREAM_TYPE_REDIRECT;
3929
            }
3930
        } else if (!strcasecmp(cmd, "URL")) {
3931
            if (redirect) {
3932
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
3933
            }
3934
        } else if (!strcasecmp(cmd, "</Redirect>")) {
3935
            if (!redirect) {
3936
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
3937
                        filename, line_num);
3938
                errors++;
3939
            }
3940
            if (!redirect->feed_filename[0]) {
3941
                fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
3942
                        filename, line_num);
3943
                errors++;
3944
            }
3945
            redirect = NULL;
3946
        } else if (!strcasecmp(cmd, "LoadModule")) {
3947
            get_arg(arg, sizeof(arg), &p);
3948
            load_module(arg);
3949
        } else {
3950
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
3951
                    filename, line_num, cmd);
3952
            errors++;
3953
        }
3954
    }
3955

    
3956
    fclose(f);
3957
    if (errors)
3958
        return -1;
3959
    else
3960
        return 0;
3961
}
3962

    
3963

    
3964
#if 0
3965
static void write_packet(FFCodec *ffenc,
3966
                         UINT8 *buf, int size)
3967
{
3968
    PacketHeader hdr;
3969
    AVCodecContext *enc = &ffenc->enc;
3970
    UINT8 *wptr;
3971
    mk_header(&hdr, enc, size);
3972
    wptr = http_fifo.wptr;
3973
    fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
3974
    fifo_write(&http_fifo, buf, size, &wptr);
3975
    /* atomic modification of wptr */
3976
    http_fifo.wptr = wptr;
3977
    ffenc->data_count += size;
3978
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
3979
}
3980
#endif
3981

    
3982
void help(void)
3983
{
3984
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
3985
           "usage: ffserver [-L] [-h] [-f configfile]\n"
3986
           "Hyper fast multi format Audio/Video streaming server\n"
3987
           "\n"
3988
           "-L            : print the LICENCE\n"
3989
           "-h            : this help\n"
3990
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
3991
           );
3992
}
3993

    
3994
void licence(void)
3995
{
3996
    printf(
3997
    "ffserver version " FFMPEG_VERSION "\n"
3998
    "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
3999
    "This library is free software; you can redistribute it and/or\n"
4000
    "modify it under the terms of the GNU Lesser General Public\n"
4001
    "License as published by the Free Software Foundation; either\n"
4002
    "version 2 of the License, or (at your option) any later version.\n"
4003
    "\n"
4004
    "This library is distributed in the hope that it will be useful,\n"
4005
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4006
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4007
    "Lesser General Public License for more details.\n"
4008
    "\n"
4009
    "You should have received a copy of the GNU Lesser General Public\n"
4010
    "License along with this library; if not, write to the Free Software\n"
4011
    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4012
    );
4013
}
4014

    
4015
static void handle_child_exit(int sig)
4016
{
4017
    pid_t pid;
4018
    int status;
4019

    
4020
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4021
        FFStream *feed;
4022

    
4023
        for (feed = first_feed; feed; feed = feed->next) {
4024
            if (feed->pid == pid) {
4025
                int uptime = time(0) - feed->pid_start;
4026

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

    
4030
                if (uptime < 30) {
4031
                    /* Turn off any more restarts */
4032
                    feed->child_argv = 0;
4033
                }    
4034
            }
4035
        }
4036
    }
4037

    
4038
    need_to_start_children = 1;
4039
}
4040

    
4041
int main(int argc, char **argv)
4042
{
4043
    const char *config_filename;
4044
    int c;
4045
    struct sigaction sigact;
4046

    
4047
    av_register_all();
4048

    
4049
    config_filename = "/etc/ffserver.conf";
4050

    
4051
    my_program_name = argv[0];
4052
    my_program_dir = getcwd(0, 0);
4053
    ffserver_daemon = 1;
4054
    
4055
    for(;;) {
4056
        c = getopt(argc, argv, "ndLh?f:");
4057
        if (c == -1)
4058
            break;
4059
        switch(c) {
4060
        case 'L':
4061
            licence();
4062
            exit(1);
4063
        case '?':
4064
        case 'h':
4065
            help();
4066
            exit(1);
4067
        case 'n':
4068
            no_launch = 1;
4069
            break;
4070
        case 'd':
4071
            ffserver_debug = 1;
4072
            ffserver_daemon = 0;
4073
            break;
4074
        case 'f':
4075
            config_filename = optarg;
4076
            break;
4077
        default:
4078
            exit(2);
4079
        }
4080
    }
4081

    
4082
    putenv("http_proxy");               /* Kill the http_proxy */
4083

    
4084
    srandom(gettime_ms() + (getpid() << 16));
4085

    
4086
    /* address on which the server will handle HTTP connections */
4087
    my_http_addr.sin_family = AF_INET;
4088
    my_http_addr.sin_port = htons (8080);
4089
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4090

    
4091
    /* address on which the server will handle RTSP connections */
4092
    my_rtsp_addr.sin_family = AF_INET;
4093
    my_rtsp_addr.sin_port = htons (5454);
4094
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4095
    
4096
    nb_max_connections = 5;
4097
    nb_max_bandwidth = 1000;
4098
    first_stream = NULL;
4099
    logfilename[0] = '\0';
4100

    
4101
    memset(&sigact, 0, sizeof(sigact));
4102
    sigact.sa_handler = handle_child_exit;
4103
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4104
    sigaction(SIGCHLD, &sigact, 0);
4105

    
4106
    if (parse_ffconfig(config_filename) < 0) {
4107
        fprintf(stderr, "Incorrect config file - exiting.\n");
4108
        exit(1);
4109
    }
4110

    
4111
    build_file_streams();
4112

    
4113
    build_feed_streams();
4114

    
4115
    /* put the process in background and detach it from its TTY */
4116
    if (ffserver_daemon) {
4117
        int pid;
4118

    
4119
        pid = fork();
4120
        if (pid < 0) {
4121
            perror("fork");
4122
            exit(1);
4123
        } else if (pid > 0) {
4124
            /* parent : exit */
4125
            exit(0);
4126
        } else {
4127
            /* child */
4128
            setsid();
4129
            chdir("/");
4130
            close(0);
4131
            open("/dev/null", O_RDWR);
4132
            if (strcmp(logfilename, "-") != 0) {
4133
                close(1);
4134
                dup(0);
4135
            }
4136
            close(2);
4137
            dup(0);
4138
        }
4139
    }
4140

    
4141
    /* signal init */
4142
    signal(SIGPIPE, SIG_IGN);
4143

    
4144
    /* open log file if needed */
4145
    if (logfilename[0] != '\0') {
4146
        if (!strcmp(logfilename, "-"))
4147
            logfile = stdout;
4148
        else
4149
            logfile = fopen(logfilename, "w");
4150
    }
4151

    
4152
    if (http_server() < 0) {
4153
        fprintf(stderr, "Could not start server\n");
4154
        exit(1);
4155
    }
4156

    
4157
    return 0;
4158
}