Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 33f25681

History | View | Annotate | Download (150 KB)

1
/*
2
 * Multiple format streaming server
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#define HAVE_AV_CONFIG_H
20
#include "common.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
#include <netinet/in.h>
35
#include <arpa/inet.h>
36
#include <netdb.h>
37
#include <signal.h>
38
#ifdef CONFIG_HAVE_DLFCN
39
#include <dlfcn.h>
40
#endif
41

    
42
#include "ffserver.h"
43

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

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

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

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

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

    
78
    "RTSP_WAIT_REQUEST",
79
    "RTSP_SEND_REPLY",
80
    "RTSP_SEND_PACKET",
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_t 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_t *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_t 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_t first_pts;            /* initial pts value */
117
    int64_t cur_pts;              /* current pts value */
118
    int pts_stream_index;       /* stream we choose as clock reference */
119
    /* output format handling */
120
    struct FFStream *stream;
121
    /* -1 is invalid stream */
122
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
123
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
124
    int switch_pending;
125
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
126
    int last_packet_sent; /* true if last data packet was sent */
127
    int suppress_log;
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_t *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_t *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
    /* RTP short term bandwidth limitation */
148
    int packet_byte_count;
149
    int packet_start_time_us; /* used for short durations (a few
150
                                 seconds max) */
151
    /* RTP/UDP specific */
152
    URLContext *rtp_handles[MAX_STREAMS];
153

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

    
159
static AVFrame dummy_frame;
160

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

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

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

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

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

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

    
232
struct sockaddr_in my_http_addr;
233
struct sockaddr_in my_rtsp_addr;
234

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

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

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

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

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

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

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

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

    
282
int nb_max_connections;
283
int nb_connections;
284

    
285
int max_bandwidth;
286
int current_bandwidth;
287

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

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

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

    
298
static FILE *logfile = NULL;
299

    
300
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...) 
301
{
302
    va_list ap;
303
    va_start(ap, fmt);
304
    
305
    if (logfile) {
306
        vfprintf(logfile, fmt, ap);
307
        fflush(logfile);
308
    }
309
    va_end(ap);
310
}
311

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

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

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

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

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

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

    
354
/* In bytes per second */
355
static int compute_datarate(DataRateData *drd, int64_t count)
356
{
357
    if (cur_time == drd->time1)
358
        return 0;
359
    
360
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
361
}
362

    
363
static int get_longterm_datarate(DataRateData *drd, int64_t count)
364
{
365
    /* You get the first 3 seconds flat out */
366
    if (cur_time - drd->time1 < 3000)
367
        return 0;
368
    return compute_datarate(drd, count);
369
}
370

    
371

    
372
static void start_children(FFStream *feed)
373
{
374
    if (no_launch)
375
        return;
376

    
377
    for (; feed; feed = feed->next) {
378
        if (feed->child_argv && !feed->pid) {
379
            feed->pid_start = time(0);
380

    
381
            feed->pid = fork();
382

    
383
            if (feed->pid < 0) {
384
                fprintf(stderr, "Unable to create children\n");
385
                exit(1);
386
            }
387
            if (!feed->pid) {
388
                /* In child */
389
                char pathname[1024];
390
                char *slash;
391
                int i;
392

    
393
                for (i = 3; i < 256; i++) {
394
                    close(i);
395
                }
396

    
397
                if (!ffserver_debug) {
398
                    i = open("/dev/null", O_RDWR);
399
                    if (i)
400
                        dup2(i, 0);
401
                    dup2(i, 1);
402
                    dup2(i, 2);
403
                    if (i)
404
                        close(i);
405
                }
406

    
407
                pstrcpy(pathname, sizeof(pathname), my_program_name);
408

    
409
                slash = strrchr(pathname, '/');
410
                if (!slash) {
411
                    slash = pathname;
412
                } else {
413
                    slash++;
414
                }
415
                strcpy(slash, "ffmpeg");
416

    
417
                /* This is needed to make relative pathnames work */
418
                chdir(my_program_dir);
419

    
420
                signal(SIGPIPE, SIG_DFL);
421

    
422
                execvp(pathname, feed->child_argv);
423

    
424
                _exit(1);
425
            }
426
        }
427
    }
428
}
429

    
430
/* open a listening socket */
431
static int socket_open_listen(struct sockaddr_in *my_addr)
432
{
433
    int server_fd, tmp;
434

    
435
    server_fd = socket(AF_INET,SOCK_STREAM,0);
436
    if (server_fd < 0) {
437
        perror ("socket");
438
        return -1;
439
    }
440
        
441
    tmp = 1;
442
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
443

    
444
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
445
        char bindmsg[32];
446
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
447
        perror (bindmsg);
448
        close(server_fd);
449
        return -1;
450
    }
451
  
452
    if (listen (server_fd, 5) < 0) {
453
        perror ("listen");
454
        close(server_fd);
455
        return -1;
456
    }
457
    fcntl(server_fd, F_SETFL, O_NONBLOCK);
458

    
459
    return server_fd;
460
}
461

    
462
/* start all multicast streams */
463
static void start_multicast(void)
464
{
465
    FFStream *stream;
466
    char session_id[32];
467
    HTTPContext *rtp_c;
468
    struct sockaddr_in dest_addr;
469
    int default_port, stream_index;
470

    
471
    default_port = 6000;
472
    for(stream = first_stream; stream != NULL; stream = stream->next) {
473
        if (stream->is_multicast) {
474
            /* open the RTP connection */
475
            snprintf(session_id, sizeof(session_id), 
476
                     "%08x%08x", (int)random(), (int)random());
477

    
478
            /* choose a port if none given */
479
            if (stream->multicast_port == 0) {
480
                stream->multicast_port = default_port;
481
                default_port += 100;
482
            }
483

    
484
            dest_addr.sin_family = AF_INET;
485
            dest_addr.sin_addr = stream->multicast_ip;
486
            dest_addr.sin_port = htons(stream->multicast_port);
487

    
488
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id, 
489
                                       RTSP_PROTOCOL_RTP_UDP_MULTICAST);
490
            if (!rtp_c) {
491
                continue;
492
            }
493
            if (open_input_stream(rtp_c, "") < 0) {
494
                fprintf(stderr, "Could not open input stream for stream '%s'\n", 
495
                        stream->filename);
496
                continue;
497
            }
498

    
499
            /* open each RTP stream */
500
            for(stream_index = 0; stream_index < stream->nb_streams; 
501
                stream_index++) {
502
                dest_addr.sin_port = htons(stream->multicast_port + 
503
                                           2 * stream_index);
504
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
505
                    fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n", 
506
                            stream->filename, stream_index);
507
                    exit(1);
508
                }
509
            }
510

    
511
            /* change state to send data */
512
            rtp_c->state = HTTPSTATE_SEND_DATA;
513
        }
514
    }
515
}
516

    
517
/* main loop of the http server */
518
static int http_server(void)
519
{
520
    int server_fd, ret, rtsp_server_fd, delay, delay1;
521
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
522
    HTTPContext *c, *c_next;
523

    
524
    server_fd = socket_open_listen(&my_http_addr);
525
    if (server_fd < 0)
526
        return -1;
527

    
528
    rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
529
    if (rtsp_server_fd < 0)
530
        return -1;
531
    
532
    http_log("ffserver started.\n");
533

    
534
    start_children(first_feed);
535

    
536
    first_http_ctx = NULL;
537
    nb_connections = 0;
538
    first_http_ctx = NULL;
539

    
540
    start_multicast();
541

    
542
    for(;;) {
543
        poll_entry = poll_table;
544
        poll_entry->fd = server_fd;
545
        poll_entry->events = POLLIN;
546
        poll_entry++;
547

    
548
        poll_entry->fd = rtsp_server_fd;
549
        poll_entry->events = POLLIN;
550
        poll_entry++;
551

    
552
        /* wait for events on each HTTP handle */
553
        c = first_http_ctx;
554
        delay = 1000;
555
        while (c != NULL) {
556
            int fd;
557
            fd = c->fd;
558
            switch(c->state) {
559
            case HTTPSTATE_SEND_HEADER:
560
            case RTSPSTATE_SEND_REPLY:
561
            case RTSPSTATE_SEND_PACKET:
562
                c->poll_entry = poll_entry;
563
                poll_entry->fd = fd;
564
                poll_entry->events = POLLOUT;
565
                poll_entry++;
566
                break;
567
            case HTTPSTATE_SEND_DATA_HEADER:
568
            case HTTPSTATE_SEND_DATA:
569
            case HTTPSTATE_SEND_DATA_TRAILER:
570
                if (!c->is_packetized) {
571
                    /* for TCP, we output as much as we can (may need to put a limit) */
572
                    c->poll_entry = poll_entry;
573
                    poll_entry->fd = fd;
574
                    poll_entry->events = POLLOUT;
575
                    poll_entry++;
576
                } else {
577
                    /* not strictly correct, but currently cannot add
578
                       more than one fd in poll entry */
579
                    delay = 0;
580
                }
581
                break;
582
            case HTTPSTATE_WAIT_REQUEST:
583
            case HTTPSTATE_RECEIVE_DATA:
584
            case HTTPSTATE_WAIT_FEED:
585
            case RTSPSTATE_WAIT_REQUEST:
586
                /* need to catch errors */
587
                c->poll_entry = poll_entry;
588
                poll_entry->fd = fd;
589
                poll_entry->events = POLLIN;/* Maybe this will work */
590
                poll_entry++;
591
                break;
592
            case HTTPSTATE_WAIT:
593
                c->poll_entry = NULL;
594
                delay1 = compute_send_delay(c);
595
                if (delay1 < delay)
596
                    delay = delay1;
597
                break;
598
            case HTTPSTATE_WAIT_SHORT:
599
                c->poll_entry = NULL;
600
                delay1 = 10; /* one tick wait XXX: 10 ms assumed */
601
                if (delay1 < delay)
602
                    delay = delay1;
603
                break;
604
            default:
605
                c->poll_entry = NULL;
606
                break;
607
            }
608
            c = c->next;
609
        }
610

    
611
        /* wait for an event on one connection. We poll at least every
612
           second to handle timeouts */
613
        do {
614
            ret = poll(poll_table, poll_entry - poll_table, delay);
615
        } while (ret == -1);
616
        
617
        cur_time = gettime_ms();
618

    
619
        if (need_to_start_children) {
620
            need_to_start_children = 0;
621
            start_children(first_feed);
622
        }
623

    
624
        /* now handle the events */
625
        for(c = first_http_ctx; c != NULL; c = c_next) {
626
            c_next = c->next;
627
            if (handle_connection(c) < 0) {
628
                /* close and free the connection */
629
                log_connection(c);
630
                close_connection(c);
631
            }
632
        }
633

    
634
        poll_entry = poll_table;
635
        /* new HTTP connection request ? */
636
        if (poll_entry->revents & POLLIN) {
637
            new_connection(server_fd, 0);
638
        }
639
        poll_entry++;
640
        /* new RTSP connection request ? */
641
        if (poll_entry->revents & POLLIN) {
642
            new_connection(rtsp_server_fd, 1);
643
        }
644
    }
645
}
646

    
647
/* start waiting for a new HTTP/RTSP request */
648
static void start_wait_request(HTTPContext *c, int is_rtsp)
649
{
650
    c->buffer_ptr = c->buffer;
651
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
652

    
653
    if (is_rtsp) {
654
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
655
        c->state = RTSPSTATE_WAIT_REQUEST;
656
    } else {
657
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
658
        c->state = HTTPSTATE_WAIT_REQUEST;
659
    }
660
}
661

    
662
static void new_connection(int server_fd, int is_rtsp)
663
{
664
    struct sockaddr_in from_addr;
665
    int fd, len;
666
    HTTPContext *c = NULL;
667

    
668
    len = sizeof(from_addr);
669
    fd = accept(server_fd, (struct sockaddr *)&from_addr, 
670
                &len);
671
    if (fd < 0)
672
        return;
673
    fcntl(fd, F_SETFL, O_NONBLOCK);
674

    
675
    /* XXX: should output a warning page when coming
676
       close to the connection limit */
677
    if (nb_connections >= nb_max_connections)
678
        goto fail;
679
    
680
    /* add a new connection */
681
    c = av_mallocz(sizeof(HTTPContext));
682
    if (!c)
683
        goto fail;
684
    
685
    c->next = first_http_ctx;
686
    first_http_ctx = c;
687
    c->fd = fd;
688
    c->poll_entry = NULL;
689
    c->from_addr = from_addr;
690
    c->buffer_size = IOBUFFER_INIT_SIZE;
691
    c->buffer = av_malloc(c->buffer_size);
692
    if (!c->buffer)
693
        goto fail;
694
    nb_connections++;
695
    
696
    start_wait_request(c, is_rtsp);
697

    
698
    return;
699

    
700
 fail:
701
    if (c) {
702
        av_free(c->buffer);
703
        av_free(c);
704
    }
705
    close(fd);
706
}
707

    
708
static void close_connection(HTTPContext *c)
709
{
710
    HTTPContext **cp, *c1;
711
    int i, nb_streams;
712
    AVFormatContext *ctx;
713
    URLContext *h;
714
    AVStream *st;
715

    
716
    /* remove connection from list */
717
    cp = &first_http_ctx;
718
    while ((*cp) != NULL) {
719
        c1 = *cp;
720
        if (c1 == c) {
721
            *cp = c->next;
722
        } else {
723
            cp = &c1->next;
724
        }
725
    }
726

    
727
    /* remove references, if any (XXX: do it faster) */
728
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
729
        if (c1->rtsp_c == c)
730
            c1->rtsp_c = NULL;
731
    }
732

    
733
    /* remove connection associated resources */
734
    if (c->fd >= 0)
735
        close(c->fd);
736
    if (c->fmt_in) {
737
        /* close each frame parser */
738
        for(i=0;i<c->fmt_in->nb_streams;i++) {
739
            st = c->fmt_in->streams[i];
740
            if (st->codec.codec) {
741
                avcodec_close(&st->codec);
742
            }
743
        }
744
        av_close_input_file(c->fmt_in);
745
    }
746

    
747
    /* free RTP output streams if any */
748
    nb_streams = 0;
749
    if (c->stream) 
750
        nb_streams = c->stream->nb_streams;
751
    
752
    for(i=0;i<nb_streams;i++) {
753
        ctx = c->rtp_ctx[i];
754
        if (ctx) {
755
            av_write_trailer(ctx);
756
            av_free(ctx);
757
        }
758
        h = c->rtp_handles[i];
759
        if (h) {
760
            url_close(h);
761
        }
762
    }
763
    
764
    ctx = &c->fmt_ctx;
765

    
766
    if (!c->last_packet_sent) {
767
        if (ctx->oformat) {
768
            /* prepare header */
769
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
770
                av_write_trailer(ctx);
771
                url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
772
            }
773
        }
774
    }
775

    
776
    for(i=0; i<ctx->nb_streams; i++) 
777
        av_free(ctx->streams[i]) ; 
778

    
779
    if (c->stream)
780
        current_bandwidth -= c->stream->bandwidth;
781
    av_freep(&c->pb_buffer);
782
    av_freep(&c->packet_buffer);
783
    av_free(c->buffer);
784
    av_free(c);
785
    nb_connections--;
786
}
787

    
788
static int handle_connection(HTTPContext *c)
789
{
790
    int len, ret;
791
    
792
    switch(c->state) {
793
    case HTTPSTATE_WAIT_REQUEST:
794
    case RTSPSTATE_WAIT_REQUEST:
795
        /* timeout ? */
796
        if ((c->timeout - cur_time) < 0)
797
            return -1;
798
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
799
            return -1;
800

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

    
834
    case HTTPSTATE_SEND_HEADER:
835
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
836
            return -1;
837

    
838
        /* no need to write if no events */
839
        if (!(c->poll_entry->revents & POLLOUT))
840
            return 0;
841
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
842
        if (len < 0) {
843
            if (errno != EAGAIN && errno != EINTR) {
844
                /* error : close connection */
845
                av_freep(&c->pb_buffer);
846
                return -1;
847
            }
848
        } else {
849
            c->buffer_ptr += len;
850
            if (c->stream)
851
                c->stream->bytes_served += len;
852
            c->data_count += len;
853
            if (c->buffer_ptr >= c->buffer_end) {
854
                av_freep(&c->pb_buffer);
855
                /* if error, exit */
856
                if (c->http_error) {
857
                    return -1;
858
                }
859
                /* all the buffer was sent : synchronize to the incoming stream */
860
                c->state = HTTPSTATE_SEND_DATA_HEADER;
861
                c->buffer_ptr = c->buffer_end = c->buffer;
862
            }
863
        }
864
        break;
865

    
866
    case HTTPSTATE_SEND_DATA:
867
    case HTTPSTATE_SEND_DATA_HEADER:
868
    case HTTPSTATE_SEND_DATA_TRAILER:
869
        /* for packetized output, we consider we can always write (the
870
           input streams sets the speed). It may be better to verify
871
           that we do not rely too much on the kernel queues */
872
        if (!c->is_packetized) {
873
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
874
                return -1;
875
            
876
            /* no need to read if no events */
877
            if (!(c->poll_entry->revents & POLLOUT))
878
                return 0;
879
        }
880
        if (http_send_data(c) < 0)
881
            return -1;
882
        break;
883
    case HTTPSTATE_RECEIVE_DATA:
884
        /* no need to read if no events */
885
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
886
            return -1;
887
        if (!(c->poll_entry->revents & POLLIN))
888
            return 0;
889
        if (http_receive_data(c) < 0)
890
            return -1;
891
        break;
892
    case HTTPSTATE_WAIT_FEED:
893
        /* no need to read if no events */
894
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
895
            return -1;
896

    
897
        /* nothing to do, we'll be waken up by incoming feed packets */
898
        break;
899

    
900
    case HTTPSTATE_WAIT:
901
        /* if the delay expired, we can send new packets */
902
        if (compute_send_delay(c) <= 0)
903
            c->state = HTTPSTATE_SEND_DATA;
904
        break;
905
    case HTTPSTATE_WAIT_SHORT:
906
        /* just return back to send data */
907
        c->state = HTTPSTATE_SEND_DATA;
908
        break;
909

    
910
    case RTSPSTATE_SEND_REPLY:
911
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
912
            av_freep(&c->pb_buffer);
913
            return -1;
914
        }
915
        /* no need to write if no events */
916
        if (!(c->poll_entry->revents & POLLOUT))
917
            return 0;
918
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
919
        if (len < 0) {
920
            if (errno != EAGAIN && errno != EINTR) {
921
                /* error : close connection */
922
                av_freep(&c->pb_buffer);
923
                return -1;
924
            }
925
        } else {
926
            c->buffer_ptr += len;
927
            c->data_count += len;
928
            if (c->buffer_ptr >= c->buffer_end) {
929
                /* all the buffer was sent : wait for a new request */
930
                av_freep(&c->pb_buffer);
931
                start_wait_request(c, 1);
932
            }
933
        }
934
        break;
935
    case RTSPSTATE_SEND_PACKET:
936
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
937
            av_freep(&c->packet_buffer);
938
            return -1;
939
        }
940
        /* no need to write if no events */
941
        if (!(c->poll_entry->revents & POLLOUT))
942
            return 0;
943
        len = write(c->fd, c->packet_buffer_ptr, 
944
                    c->packet_buffer_end - c->packet_buffer_ptr);
945
        if (len < 0) {
946
            if (errno != EAGAIN && errno != EINTR) {
947
                /* error : close connection */
948
                av_freep(&c->packet_buffer);
949
                return -1;
950
            }
951
        } else {
952
            c->packet_buffer_ptr += len;
953
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
954
                /* all the buffer was sent : wait for a new request */
955
                av_freep(&c->packet_buffer);
956
                c->state = RTSPSTATE_WAIT_REQUEST;
957
            }
958
        }
959
        break;
960
    case HTTPSTATE_READY:
961
        /* nothing to do */
962
        break;
963
    default:
964
        return -1;
965
    }
966
    return 0;
967
}
968

    
969
static int extract_rates(char *rates, int ratelen, const char *request)
970
{
971
    const char *p;
972

    
973
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
974
        if (strncasecmp(p, "Pragma:", 7) == 0) {
975
            const char *q = p + 7;
976

    
977
            while (*q && *q != '\n' && isspace(*q))
978
                q++;
979

    
980
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
981
                int stream_no;
982
                int rate_no;
983

    
984
                q += 20;
985

    
986
                memset(rates, 0xff, ratelen);
987

    
988
                while (1) {
989
                    while (*q && *q != '\n' && *q != ':')
990
                        q++;
991

    
992
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
993
                        break;
994
                    }
995
                    stream_no--;
996
                    if (stream_no < ratelen && stream_no >= 0) {
997
                        rates[stream_no] = rate_no;
998
                    }
999

    
1000
                    while (*q && *q != '\n' && !isspace(*q))
1001
                        q++;
1002
                }
1003

    
1004
                return 1;
1005
            }
1006
        }
1007
        p = strchr(p, '\n');
1008
        if (!p)
1009
            break;
1010

    
1011
        p++;
1012
    }
1013

    
1014
    return 0;
1015
}
1016

    
1017
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1018
{
1019
    int i;
1020
    int best_bitrate = 100000000;
1021
    int best = -1;
1022

    
1023
    for (i = 0; i < feed->nb_streams; i++) {
1024
        AVCodecContext *feed_codec = &feed->streams[i]->codec;
1025

    
1026
        if (feed_codec->codec_id != codec->codec_id ||
1027
            feed_codec->sample_rate != codec->sample_rate ||
1028
            feed_codec->width != codec->width ||
1029
            feed_codec->height != codec->height) {
1030
            continue;
1031
        }
1032

    
1033
        /* Potential stream */
1034

    
1035
        /* We want the fastest stream less than bit_rate, or the slowest 
1036
         * faster than bit_rate
1037
         */
1038

    
1039
        if (feed_codec->bit_rate <= bit_rate) {
1040
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1041
                best_bitrate = feed_codec->bit_rate;
1042
                best = i;
1043
            }
1044
        } else {
1045
            if (feed_codec->bit_rate < best_bitrate) {
1046
                best_bitrate = feed_codec->bit_rate;
1047
                best = i;
1048
            }
1049
        }
1050
    }
1051

    
1052
    return best;
1053
}
1054

    
1055
static int modify_current_stream(HTTPContext *c, char *rates)
1056
{
1057
    int i;
1058
    FFStream *req = c->stream;
1059
    int action_required = 0;
1060

    
1061
    /* Not much we can do for a feed */
1062
    if (!req->feed)
1063
        return 0;
1064

    
1065
    for (i = 0; i < req->nb_streams; i++) {
1066
        AVCodecContext *codec = &req->streams[i]->codec;
1067

    
1068
        switch(rates[i]) {
1069
            case 0:
1070
                c->switch_feed_streams[i] = req->feed_streams[i];
1071
                break;
1072
            case 1:
1073
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1074
                break;
1075
            case 2:
1076
                /* Wants off or slow */
1077
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1078
#ifdef WANTS_OFF
1079
                /* This doesn't work well when it turns off the only stream! */
1080
                c->switch_feed_streams[i] = -2;
1081
                c->feed_streams[i] = -2;
1082
#endif
1083
                break;
1084
        }
1085

    
1086
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1087
            action_required = 1;
1088
    }
1089

    
1090
    return action_required;
1091
}
1092

    
1093

    
1094
static void do_switch_stream(HTTPContext *c, int i)
1095
{
1096
    if (c->switch_feed_streams[i] >= 0) {
1097
#ifdef PHILIP        
1098
        c->feed_streams[i] = c->switch_feed_streams[i];
1099
#endif
1100

    
1101
        /* Now update the stream */
1102
    }
1103
    c->switch_feed_streams[i] = -1;
1104
}
1105

    
1106
/* XXX: factorize in utils.c ? */
1107
/* XXX: take care with different space meaning */
1108
static void skip_spaces(const char **pp)
1109
{
1110
    const char *p;
1111
    p = *pp;
1112
    while (*p == ' ' || *p == '\t')
1113
        p++;
1114
    *pp = p;
1115
}
1116

    
1117
static void get_word(char *buf, int buf_size, const char **pp)
1118
{
1119
    const char *p;
1120
    char *q;
1121

    
1122
    p = *pp;
1123
    skip_spaces(&p);
1124
    q = buf;
1125
    while (!isspace(*p) && *p != '\0') {
1126
        if ((q - buf) < buf_size - 1)
1127
            *q++ = *p;
1128
        p++;
1129
    }
1130
    if (buf_size > 0)
1131
        *q = '\0';
1132
    *pp = p;
1133
}
1134

    
1135
static int validate_acl(FFStream *stream, HTTPContext *c)
1136
{
1137
    enum IPAddressAction last_action = IP_DENY;
1138
    IPAddressACL *acl;
1139
    struct in_addr *src = &c->from_addr.sin_addr;
1140
    unsigned long src_addr = ntohl(src->s_addr);
1141

    
1142
    for (acl = stream->acl; acl; acl = acl->next) {
1143
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1144
            return (acl->action == IP_ALLOW) ? 1 : 0;
1145
        }
1146
        last_action = acl->action;
1147
    }
1148

    
1149
    /* Nothing matched, so return not the last action */
1150
    return (last_action == IP_DENY) ? 1 : 0;
1151
}
1152

    
1153
/* compute the real filename of a file by matching it without its
1154
   extensions to all the stream filenames */
1155
static void compute_real_filename(char *filename, int max_size)
1156
{
1157
    char file1[1024];
1158
    char file2[1024];
1159
    char *p;
1160
    FFStream *stream;
1161

    
1162
    /* compute filename by matching without the file extensions */
1163
    pstrcpy(file1, sizeof(file1), filename);
1164
    p = strrchr(file1, '.');
1165
    if (p)
1166
        *p = '\0';
1167
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1168
        pstrcpy(file2, sizeof(file2), stream->filename);
1169
        p = strrchr(file2, '.');
1170
        if (p)
1171
            *p = '\0';
1172
        if (!strcmp(file1, file2)) {
1173
            pstrcpy(filename, max_size, stream->filename);
1174
            break;
1175
        }
1176
    }
1177
}
1178

    
1179
enum RedirType {
1180
    REDIR_NONE,
1181
    REDIR_ASX,
1182
    REDIR_RAM,
1183
    REDIR_ASF,
1184
    REDIR_RTSP,
1185
    REDIR_SDP,
1186
};
1187

    
1188
/* parse http request and prepare header */
1189
static int http_parse_request(HTTPContext *c)
1190
{
1191
    char *p;
1192
    int post;
1193
    enum RedirType redir_type;
1194
    char cmd[32];
1195
    char info[1024], *filename;
1196
    char url[1024], *q;
1197
    char protocol[32];
1198
    char msg[1024];
1199
    const char *mime_type;
1200
    FFStream *stream;
1201
    int i;
1202
    char ratebuf[32];
1203
    char *useragent = 0;
1204

    
1205
    p = c->buffer;
1206
    get_word(cmd, sizeof(cmd), (const char **)&p);
1207
    pstrcpy(c->method, sizeof(c->method), cmd);
1208

    
1209
    if (!strcmp(cmd, "GET"))
1210
        post = 0;
1211
    else if (!strcmp(cmd, "POST"))
1212
        post = 1;
1213
    else
1214
        return -1;
1215

    
1216
    get_word(url, sizeof(url), (const char **)&p);
1217
    pstrcpy(c->url, sizeof(c->url), url);
1218

    
1219
    get_word(protocol, sizeof(protocol), (const char **)&p);
1220
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1221
        return -1;
1222

    
1223
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1224
    
1225
    /* find the filename and the optional info string in the request */
1226
    p = url;
1227
    if (*p == '/')
1228
        p++;
1229
    filename = p;
1230
    p = strchr(p, '?');
1231
    if (p) {
1232
        pstrcpy(info, sizeof(info), p);
1233
        *p = '\0';
1234
    } else {
1235
        info[0] = '\0';
1236
    }
1237

    
1238
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1239
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1240
            useragent = p + 11;
1241
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1242
                useragent++;
1243
            break;
1244
        }
1245
        p = strchr(p, '\n');
1246
        if (!p)
1247
            break;
1248

    
1249
        p++;
1250
    }
1251

    
1252
    redir_type = REDIR_NONE;
1253
    if (match_ext(filename, "asx")) {
1254
        redir_type = REDIR_ASX;
1255
        filename[strlen(filename)-1] = 'f';
1256
    } else if (match_ext(filename, "asf") &&
1257
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1258
        /* if this isn't WMP or lookalike, return the redirector file */
1259
        redir_type = REDIR_ASF;
1260
    } else if (match_ext(filename, "rpm,ram")) {
1261
        redir_type = REDIR_RAM;
1262
        strcpy(filename + strlen(filename)-2, "m");
1263
    } else if (match_ext(filename, "rtsp")) {
1264
        redir_type = REDIR_RTSP;
1265
        compute_real_filename(filename, sizeof(url) - 1);
1266
    } else if (match_ext(filename, "sdp")) {
1267
        redir_type = REDIR_SDP;
1268
        compute_real_filename(filename, sizeof(url) - 1);
1269
    }
1270
    
1271
    stream = first_stream;
1272
    while (stream != NULL) {
1273
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1274
            break;
1275
        stream = stream->next;
1276
    }
1277
    if (stream == NULL) {
1278
        sprintf(msg, "File '%s' not found", url);
1279
        goto send_error;
1280
    }
1281

    
1282
    c->stream = stream;
1283
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1284
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1285

    
1286
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1287
        c->http_error = 301;
1288
        q = c->buffer;
1289
        q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1290
        q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1291
        q += sprintf(q, "Content-type: text/html\r\n");
1292
        q += sprintf(q, "\r\n");
1293
        q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1294
        q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1295
        q += sprintf(q, "</body></html>\r\n");
1296

    
1297
        /* prepare output buffer */
1298
        c->buffer_ptr = c->buffer;
1299
        c->buffer_end = q;
1300
        c->state = HTTPSTATE_SEND_HEADER;
1301
        return 0;
1302
    }
1303

    
1304
    /* If this is WMP, get the rate information */
1305
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1306
        if (modify_current_stream(c, ratebuf)) {
1307
            for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1308
                if (c->switch_feed_streams[i] >= 0)
1309
                    do_switch_stream(c, i);
1310
            }
1311
        }
1312
    }
1313

    
1314
    if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1315
        current_bandwidth += stream->bandwidth;
1316
    }
1317
    
1318
    if (post == 0 && max_bandwidth < current_bandwidth) {
1319
        c->http_error = 200;
1320
        q = c->buffer;
1321
        q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1322
        q += sprintf(q, "Content-type: text/html\r\n");
1323
        q += sprintf(q, "\r\n");
1324
        q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1325
        q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1326
        q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1327
            current_bandwidth, max_bandwidth);
1328
        q += sprintf(q, "</body></html>\r\n");
1329

    
1330
        /* prepare output buffer */
1331
        c->buffer_ptr = c->buffer;
1332
        c->buffer_end = q;
1333
        c->state = HTTPSTATE_SEND_HEADER;
1334
        return 0;
1335
    }
1336
    
1337
    if (redir_type != REDIR_NONE) {
1338
        char *hostinfo = 0;
1339
        
1340
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1341
            if (strncasecmp(p, "Host:", 5) == 0) {
1342
                hostinfo = p + 5;
1343
                break;
1344
            }
1345
            p = strchr(p, '\n');
1346
            if (!p)
1347
                break;
1348

    
1349
            p++;
1350
        }
1351

    
1352
        if (hostinfo) {
1353
            char *eoh;
1354
            char hostbuf[260];
1355

    
1356
            while (isspace(*hostinfo))
1357
                hostinfo++;
1358

    
1359
            eoh = strchr(hostinfo, '\n');
1360
            if (eoh) {
1361
                if (eoh[-1] == '\r')
1362
                    eoh--;
1363

    
1364
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1365
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1366
                    hostbuf[eoh - hostinfo] = 0;
1367

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

    
1420
                            q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1421
                            q += sprintf(q, "Content-type: application/sdp\r\n");
1422
                            q += sprintf(q, "\r\n");
1423

    
1424
                            len = sizeof(my_addr);
1425
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1426
                            
1427
                            /* XXX: should use a dynamic buffer */
1428
                            sdp_data_size = prepare_sdp_description(stream, 
1429
                                                                    &sdp_data, 
1430
                                                                    my_addr.sin_addr);
1431
                            if (sdp_data_size > 0) {
1432
                                memcpy(q, sdp_data, sdp_data_size);
1433
                                q += sdp_data_size;
1434
                                *q = '\0';
1435
                                av_free(sdp_data);
1436
                            }
1437
                        }
1438
                        break;
1439
                    default:
1440
                        av_abort();
1441
                        break;
1442
                    }
1443

    
1444
                    /* prepare output buffer */
1445
                    c->buffer_ptr = c->buffer;
1446
                    c->buffer_end = q;
1447
                    c->state = HTTPSTATE_SEND_HEADER;
1448
                    return 0;
1449
                }
1450
            }
1451
        }
1452

    
1453
        sprintf(msg, "ASX/RAM file not handled");
1454
        goto send_error;
1455
    }
1456

    
1457
    stream->conns_served++;
1458

    
1459
    /* XXX: add there authenticate and IP match */
1460

    
1461
    if (post) {
1462
        /* if post, it means a feed is being sent */
1463
        if (!stream->is_feed) {
1464
            /* However it might be a status report from WMP! Lets log the data
1465
             * as it might come in handy one day
1466
             */
1467
            char *logline = 0;
1468
            int client_id = 0;
1469
            
1470
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1471
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1472
                    logline = p;
1473
                    break;
1474
                }
1475
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1476
                    client_id = strtol(p + 18, 0, 10);
1477
                }
1478
                p = strchr(p, '\n');
1479
                if (!p)
1480
                    break;
1481

    
1482
                p++;
1483
            }
1484

    
1485
            if (logline) {
1486
                char *eol = strchr(logline, '\n');
1487

    
1488
                logline += 17;
1489

    
1490
                if (eol) {
1491
                    if (eol[-1] == '\r')
1492
                        eol--;
1493
                    http_log("%.*s\n", eol - logline, logline);
1494
                    c->suppress_log = 1;
1495
                }
1496
            }
1497

    
1498
#ifdef DEBUG_WMP
1499
            http_log("\nGot request:\n%s\n", c->buffer);
1500
#endif
1501

    
1502
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1503
                HTTPContext *wmpc;
1504

    
1505
                /* Now we have to find the client_id */
1506
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1507
                    if (wmpc->wmp_client_id == client_id)
1508
                        break;
1509
                }
1510

    
1511
                if (wmpc) {
1512
                    if (modify_current_stream(wmpc, ratebuf)) {
1513
                        wmpc->switch_pending = 1;
1514
                    }
1515
                }
1516
            }
1517
            
1518
            sprintf(msg, "POST command not handled");
1519
            c->stream = 0;
1520
            goto send_error;
1521
        }
1522
        if (http_start_receive_data(c) < 0) {
1523
            sprintf(msg, "could not open feed");
1524
            goto send_error;
1525
        }
1526
        c->http_error = 0;
1527
        c->state = HTTPSTATE_RECEIVE_DATA;
1528
        return 0;
1529
    }
1530

    
1531
#ifdef DEBUG_WMP
1532
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1533
        http_log("\nGot request:\n%s\n", c->buffer);
1534
    }
1535
#endif
1536

    
1537
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1538
        goto send_stats;
1539

    
1540
    /* open input stream */
1541
    if (open_input_stream(c, info) < 0) {
1542
        sprintf(msg, "Input stream corresponding to '%s' not found", url);
1543
        goto send_error;
1544
    }
1545

    
1546
    /* prepare http header */
1547
    q = c->buffer;
1548
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1549
    mime_type = c->stream->fmt->mime_type;
1550
    if (!mime_type)
1551
        mime_type = "application/x-octet_stream";
1552
    q += sprintf(q, "Pragma: no-cache\r\n");
1553

    
1554
    /* for asf, we need extra headers */
1555
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1556
        /* Need to allocate a client id */
1557

    
1558
        c->wmp_client_id = random() & 0x7fffffff;
1559

    
1560
        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);
1561
    }
1562
    q += sprintf(q, "Content-Type: %s\r\n", mime_type);
1563
    q += sprintf(q, "\r\n");
1564
    
1565
    /* prepare output buffer */
1566
    c->http_error = 0;
1567
    c->buffer_ptr = c->buffer;
1568
    c->buffer_end = q;
1569
    c->state = HTTPSTATE_SEND_HEADER;
1570
    return 0;
1571
 send_error:
1572
    c->http_error = 404;
1573
    q = c->buffer;
1574
    q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1575
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
1576
    q += sprintf(q, "\r\n");
1577
    q += sprintf(q, "<HTML>\n");
1578
    q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1579
    q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1580
    q += sprintf(q, "</HTML>\n");
1581

    
1582
    /* prepare output buffer */
1583
    c->buffer_ptr = c->buffer;
1584
    c->buffer_end = q;
1585
    c->state = HTTPSTATE_SEND_HEADER;
1586
    return 0;
1587
 send_stats:
1588
    compute_stats(c);
1589
    c->http_error = 200; /* horrible : we use this value to avoid
1590
                            going to the send data state */
1591
    c->state = HTTPSTATE_SEND_HEADER;
1592
    return 0;
1593
}
1594

    
1595
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1596
{
1597
    static const char *suffix = " kMGTP";
1598
    const char *s;
1599

    
1600
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1601
    }
1602

    
1603
    url_fprintf(pb, "%lld%c", count, *s);
1604
}
1605

    
1606
static void compute_stats(HTTPContext *c)
1607
{
1608
    HTTPContext *c1;
1609
    FFStream *stream;
1610
    char *p;
1611
    time_t ti;
1612
    int i, len;
1613
    ByteIOContext pb1, *pb = &pb1;
1614

    
1615
    if (url_open_dyn_buf(pb) < 0) {
1616
        /* XXX: return an error ? */
1617
        c->buffer_ptr = c->buffer;
1618
        c->buffer_end = c->buffer;
1619
        return;
1620
    }
1621

    
1622
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1623
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1624
    url_fprintf(pb, "Pragma: no-cache\r\n");
1625
    url_fprintf(pb, "\r\n");
1626
    
1627
    url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1628
    if (c->stream->feed_filename) {
1629
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1630
    }
1631
    url_fprintf(pb, "</HEAD>\n<BODY>");
1632
    url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1633
    /* format status */
1634
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1635
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1636
    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");
1637
    stream = first_stream;
1638
    while (stream != NULL) {
1639
        char sfilename[1024];
1640
        char *eosf;
1641

    
1642
        if (stream->feed != stream) {
1643
            pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1644
            eosf = sfilename + strlen(sfilename);
1645
            if (eosf - sfilename >= 4) {
1646
                if (strcmp(eosf - 4, ".asf") == 0) {
1647
                    strcpy(eosf - 4, ".asx");
1648
                } else if (strcmp(eosf - 3, ".rm") == 0) {
1649
                    strcpy(eosf - 3, ".ram");
1650
                } else if (stream->fmt == &rtp_mux) {
1651
                    /* generate a sample RTSP director if
1652
                       unicast. Generate an SDP redirector if
1653
                       multicast */
1654
                    eosf = strrchr(sfilename, '.');
1655
                    if (!eosf)
1656
                        eosf = sfilename + strlen(sfilename);
1657
                    if (stream->is_multicast)
1658
                        strcpy(eosf, ".sdp");
1659
                    else
1660
                        strcpy(eosf, ".rtsp");
1661
                }
1662
            }
1663
            
1664
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
1665
                         sfilename, stream->filename);
1666
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1667
                        stream->conns_served);
1668
            fmt_bytecount(pb, stream->bytes_served);
1669
            switch(stream->stream_type) {
1670
            case STREAM_TYPE_LIVE:
1671
                {
1672
                    int audio_bit_rate = 0;
1673
                    int video_bit_rate = 0;
1674
                    const char *audio_codec_name = "";
1675
                    const char *video_codec_name = "";
1676
                    const char *audio_codec_name_extra = "";
1677
                    const char *video_codec_name_extra = "";
1678

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

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

    
1732
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1733
                {
1734
                    FILE *pid_stat;
1735
                    char ps_cmd[64];
1736

    
1737
                    /* This is somewhat linux specific I guess */
1738
                    snprintf(ps_cmd, sizeof(ps_cmd), 
1739
                             "ps -o \"%%cpu,cputime\" --no-headers %d", 
1740
                             stream->pid);
1741
                    
1742
                    pid_stat = popen(ps_cmd, "r");
1743
                    if (pid_stat) {
1744
                        char cpuperc[10];
1745
                        char cpuused[64];
1746
                        
1747
                        if (fscanf(pid_stat, "%10s %64s", cpuperc, 
1748
                                   cpuused) == 2) {
1749
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1750
                                         cpuperc, cpuused);
1751
                        }
1752
                        fclose(pid_stat);
1753
                    }
1754
                }
1755
#endif
1756

    
1757
                url_fprintf(pb, "<p>");
1758
            }
1759
            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");
1760

    
1761
            for (i = 0; i < stream->nb_streams; i++) {
1762
                AVStream *st = stream->streams[i];
1763
                AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1764
                const char *type = "unknown";
1765
                char parameters[64];
1766

    
1767
                parameters[0] = 0;
1768

    
1769
                switch(st->codec.codec_type) {
1770
                case CODEC_TYPE_AUDIO:
1771
                    type = "audio";
1772
                    break;
1773
                case CODEC_TYPE_VIDEO:
1774
                    type = "video";
1775
                    sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
1776
                                st->codec.qmin, st->codec.qmax, st->codec.frame_rate / st->codec.frame_rate_base);
1777
                    break;
1778
                default:
1779
                    av_abort();
1780
                }
1781
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1782
                        i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
1783
            }
1784
            url_fprintf(pb, "</table>\n");
1785

    
1786
        }       
1787
        stream = stream->next;
1788
    }
1789
    
1790
#if 0
1791
    {
1792
        float avg;
1793
        AVCodecContext *enc;
1794
        char buf[1024];
1795
        
1796
        /* feed status */
1797
        stream = first_feed;
1798
        while (stream != NULL) {
1799
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1800
            url_fprintf(pb, "<TABLE>\n");
1801
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1802
            for(i=0;i<stream->nb_streams;i++) {
1803
                AVStream *st = stream->streams[i];
1804
                FeedData *fdata = st->priv_data;
1805
                enc = &st->codec;
1806
            
1807
                avcodec_string(buf, sizeof(buf), enc);
1808
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1809
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1810
                    avg /= enc->frame_size;
1811
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
1812
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1813
            }
1814
            url_fprintf(pb, "</TABLE>\n");
1815
            stream = stream->next_feed;
1816
        }
1817
    }
1818
#endif
1819

    
1820
    /* connection status */
1821
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1822

    
1823
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1824
                 nb_connections, nb_max_connections);
1825

    
1826
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1827
                 current_bandwidth, max_bandwidth);
1828

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

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

    
1850
        i++;
1851
        p = inet_ntoa(c1->from_addr.sin_addr);
1852
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>", 
1853
                    i, 
1854
                    c1->stream ? c1->stream->filename : "", 
1855
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1856
                    p, 
1857
                    c1->protocol,
1858
                    http_state[c1->state]);
1859
        fmt_bytecount(pb, bitrate);
1860
        url_fprintf(pb, "<td align=right>");
1861
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1862
        url_fprintf(pb, "<td align=right>");
1863
        fmt_bytecount(pb, c1->data_count);
1864
        url_fprintf(pb, "\n");
1865
        c1 = c1->next;
1866
    }
1867
    url_fprintf(pb, "</TABLE>\n");
1868
    
1869
    /* date */
1870
    ti = time(NULL);
1871
    p = ctime(&ti);
1872
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1873
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1874

    
1875
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1876
    c->buffer_ptr = c->pb_buffer;
1877
    c->buffer_end = c->pb_buffer + len;
1878
}
1879

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

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

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

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

    
1931
#if 0
1932
    { time_t when = stream_pos / 1000000;
1933
    http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1934
    }
1935
#endif
1936

    
1937
    /* open stream */
1938
    if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1939
        http_log("%s not found", input_filename);
1940
        return -1;
1941
    }
1942
    c->fmt_in = s;
1943
    
1944
    /* open each parser */
1945
    for(i=0;i<s->nb_streams;i++)
1946
        open_parser(s, i);
1947

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

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

    
1967
/* currently desactivated because the new PTS handling is not
1968
   satisfactory yet */
1969
//#define AV_READ_FRAME
1970
#ifdef AV_READ_FRAME
1971

    
1972
/* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1973
   the return packet MUST NOT be freed */
1974
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1975
{
1976
    AVStream *st;
1977
    int len, ret, old_nb_streams, i;
1978

    
1979
    /* see if remaining frames must be parsed */
1980
    for(;;) {
1981
        if (s->cur_len > 0) {
1982
            st = s->streams[s->cur_pkt.stream_index];
1983
            len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size, 
1984
                                      s->cur_ptr, s->cur_len);
1985
            if (len < 0) {
1986
                /* error: get next packet */
1987
                s->cur_len = 0;
1988
            } else {
1989
                s->cur_ptr += len;
1990
                s->cur_len -= len;
1991
                if (pkt->size) {
1992
                    /* init pts counter if not done */
1993
                    if (st->pts.den == 0) {
1994
                        switch(st->codec.codec_type) {
1995
                        case CODEC_TYPE_AUDIO:
1996
                            st->pts_incr = (int64_t)s->pts_den;
1997
                            av_frac_init(&st->pts, st->pts.val, 0, 
1998
                                         (int64_t)s->pts_num * st->codec.sample_rate);
1999
                            break;
2000
                        case CODEC_TYPE_VIDEO:
2001
                            st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
2002
                            av_frac_init(&st->pts, st->pts.val, 0,
2003
                                         (int64_t)s->pts_num * st->codec.frame_rate);
2004
                            break;
2005
                        default:
2006
                            av_abort();
2007
                        }
2008
                    }
2009
                    
2010
                    /* a frame was read: return it */
2011
                    pkt->pts = st->pts.val;
2012
#if 0
2013
                    printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
2014
                           st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
2015
#endif
2016
                    switch(st->codec.codec_type) {
2017
                    case CODEC_TYPE_AUDIO:
2018
                        av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
2019
                        break;
2020
                    case CODEC_TYPE_VIDEO:
2021
                        av_frac_add(&st->pts, st->pts_incr);
2022
                        break;
2023
                    default:
2024
                        av_abort();
2025
                    }
2026
                    pkt->stream_index = s->cur_pkt.stream_index;
2027
                    /* we use the codec indication because it is
2028
                       more accurate than the demux flags */
2029
                    pkt->flags = 0;
2030
                    if (st->codec.coded_frame->key_frame) 
2031
                        pkt->flags |= PKT_FLAG_KEY;
2032
                    return 0;
2033
                }
2034
            }
2035
        } else {
2036
            /* free previous packet */
2037
            av_free_packet(&s->cur_pkt); 
2038

    
2039
            old_nb_streams = s->nb_streams;
2040
            ret = av_read_packet(s, &s->cur_pkt);
2041
            if (ret)
2042
                return ret;
2043
            /* open parsers for each new streams */
2044
            for(i = old_nb_streams; i < s->nb_streams; i++)
2045
                open_parser(s, i);
2046
            st = s->streams[s->cur_pkt.stream_index];
2047

    
2048
            /* update current pts (XXX: dts handling) from packet, or
2049
               use current pts if none given */
2050
            if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
2051
                av_frac_set(&st->pts, s->cur_pkt.pts);
2052
            } else {
2053
                s->cur_pkt.pts = st->pts.val;
2054
            }
2055
            if (!st->codec.codec) {
2056
                /* no codec opened: just return the raw packet */
2057
                *pkt = s->cur_pkt;
2058

    
2059
                /* no codec opened: just update the pts by considering we
2060
                   have one frame and free the packet */
2061
                if (st->pts.den == 0) {
2062
                    switch(st->codec.codec_type) {
2063
                    case CODEC_TYPE_AUDIO:
2064
                        st->pts_incr = (int64_t)s->pts_den * st->codec.frame_size;
2065
                        av_frac_init(&st->pts, st->pts.val, 0, 
2066
                                     (int64_t)s->pts_num * st->codec.sample_rate);
2067
                        break;
2068
                    case CODEC_TYPE_VIDEO:
2069
                        st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base;
2070
                        av_frac_init(&st->pts, st->pts.val, 0,
2071
                                     (int64_t)s->pts_num * st->codec.frame_rate);
2072
                        break;
2073
                    default:
2074
                        av_abort();
2075
                    }
2076
                }
2077
                av_frac_add(&st->pts, st->pts_incr);
2078
                return 0;
2079
            } else {
2080
                s->cur_ptr = s->cur_pkt.data;
2081
                s->cur_len = s->cur_pkt.size;
2082
            }
2083
        }
2084
    }
2085
}
2086

    
2087
static int compute_send_delay(HTTPContext *c)
2088
{
2089
    int64_t cur_pts, delta_pts, next_pts;
2090
    int delay1;
2091
    
2092
    /* compute current pts value from system time */
2093
    cur_pts = ((int64_t)(cur_time - c->start_time) * c->fmt_in->pts_den) / 
2094
        (c->fmt_in->pts_num * 1000LL);
2095
    /* compute the delta from the stream we choose as
2096
       main clock (we do that to avoid using explicit
2097
       buffers to do exact packet reordering for each
2098
       stream */
2099
    /* XXX: really need to fix the number of streams */
2100
    if (c->pts_stream_index >= c->fmt_in->nb_streams)
2101
        next_pts = cur_pts;
2102
    else
2103
        next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
2104
    delta_pts = next_pts - cur_pts;
2105
    if (delta_pts <= 0) {
2106
        delay1 = 0;
2107
    } else {
2108
        delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
2109
    }
2110
    return delay1;
2111
}
2112
#else
2113

    
2114
/* just fall backs */
2115
static int av_read_frame(AVFormatContext *s, AVPacket *pkt)
2116
{
2117
    return av_read_packet(s, pkt);
2118
}
2119

    
2120
static int compute_send_delay(HTTPContext *c)
2121
{
2122
    int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count); 
2123
    int64_t delta_pts;
2124
    int64_t time_pts;
2125
    int m_delay;
2126

    
2127
    if (datarate > c->stream->bandwidth * 2000) {
2128
        return 1000;
2129
    }
2130
    if (!c->stream->feed && c->first_pts!=AV_NOPTS_VALUE) {
2131
        time_pts = ((int64_t)(cur_time - c->start_time) * c->fmt_in->pts_den) / 
2132
            ((int64_t) c->fmt_in->pts_num*1000);
2133
        delta_pts = c->cur_pts - time_pts;
2134
        m_delay = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
2135
        return m_delay>0 ? m_delay : 0;
2136
    } else {
2137
        return 0;
2138
    }
2139
}
2140

    
2141
#endif
2142
    
2143
static int http_prepare_data(HTTPContext *c)
2144
{
2145
    int i, len, ret;
2146
    AVFormatContext *ctx;
2147

    
2148
    av_freep(&c->pb_buffer);
2149
    switch(c->state) {
2150
    case HTTPSTATE_SEND_DATA_HEADER:
2151
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2152
        pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), 
2153
                c->stream->author);
2154
        pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), 
2155
                c->stream->comment);
2156
        pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), 
2157
                c->stream->copyright);
2158
        pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), 
2159
                c->stream->title);
2160

    
2161
        /* open output stream by using specified codecs */
2162
        c->fmt_ctx.oformat = c->stream->fmt;
2163
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2164
        for(i=0;i<c->fmt_ctx.nb_streams;i++) {
2165
            AVStream *st;
2166
            st = av_mallocz(sizeof(AVStream));
2167
            c->fmt_ctx.streams[i] = st;
2168
            /* if file or feed, then just take streams from FFStream struct */
2169
            if (!c->stream->feed || 
2170
                c->stream->feed == c->stream)
2171
                memcpy(st, c->stream->streams[i], sizeof(AVStream));
2172
            else
2173
                memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
2174
                           sizeof(AVStream));
2175
            st->codec.frame_number = 0; /* XXX: should be done in
2176
                                           AVStream, not in codec */
2177
            /* I'm pretty sure that this is not correct...
2178
             * However, without it, we crash
2179
             */
2180
            st->codec.coded_frame = &dummy_frame;
2181
        }
2182
        c->got_key_frame = 0;
2183

    
2184
        /* prepare header and save header data in a stream */
2185
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2186
            /* XXX: potential leak */
2187
            return -1;
2188
        }
2189
        c->fmt_ctx.pb.is_streamed = 1;
2190

    
2191
        av_set_parameters(&c->fmt_ctx, NULL);
2192
        av_write_header(&c->fmt_ctx);
2193

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

    
2198
        c->state = HTTPSTATE_SEND_DATA;
2199
        c->last_packet_sent = 0;
2200
        break;
2201
    case HTTPSTATE_SEND_DATA:
2202
        /* find a new packet */
2203
        {
2204
            AVPacket pkt;
2205
            
2206
            /* read a packet from the input stream */
2207
            if (c->stream->feed) {
2208
                ffm_set_write_index(c->fmt_in, 
2209
                                    c->stream->feed->feed_write_index,
2210
                                    c->stream->feed->feed_size);
2211
            }
2212

    
2213
            if (c->stream->max_time && 
2214
                c->stream->max_time + c->start_time - cur_time < 0) {
2215
                /* We have timed out */
2216
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
2217
            } else {
2218
                if (1 || c->is_packetized) {
2219
                    if (compute_send_delay(c) > 0) {
2220
                        c->state = HTTPSTATE_WAIT;
2221
                        return 1; /* state changed */
2222
                    }
2223
                }
2224
            redo:
2225
                if (av_read_frame(c->fmt_in, &pkt) < 0) {
2226
                    if (c->stream->feed && c->stream->feed->feed_opened) {
2227
                        /* if coming from feed, it means we reached the end of the
2228
                           ffm file, so must wait for more data */
2229
                        c->state = HTTPSTATE_WAIT_FEED;
2230
                        return 1; /* state changed */
2231
                    } else {
2232
                        if (c->stream->loop) {
2233
                            av_close_input_file(c->fmt_in);
2234
                            c->fmt_in = NULL;
2235
                            if (open_input_stream(c, "") < 0)
2236
                                goto no_loop;
2237
                            goto redo;
2238
                        } else {
2239
                        no_loop:
2240
                            /* must send trailer now because eof or error */
2241
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2242
                        }
2243
                    }
2244
                } else {
2245
                    /* update first pts if needed */
2246
                    if (c->first_pts == AV_NOPTS_VALUE) {
2247
                        c->first_pts = pkt.pts;
2248
                        c->start_time = cur_time;
2249
                    }
2250
                    c->cur_pts = pkt.pts;
2251
                    /* send it to the appropriate stream */
2252
                    if (c->stream->feed) {
2253
                        /* if coming from a feed, select the right stream */
2254
                        if (c->switch_pending) {
2255
                            c->switch_pending = 0;
2256
                            for(i=0;i<c->stream->nb_streams;i++) {
2257
                                if (c->switch_feed_streams[i] == pkt.stream_index) {
2258
                                    if (pkt.flags & PKT_FLAG_KEY) {
2259
                                        do_switch_stream(c, i);
2260
                                    }
2261
                                }
2262
                                if (c->switch_feed_streams[i] >= 0) {
2263
                                    c->switch_pending = 1;
2264
                                }
2265
                            }
2266
                        }
2267
                        for(i=0;i<c->stream->nb_streams;i++) {
2268
                            if (c->feed_streams[i] == pkt.stream_index) {
2269
                                pkt.stream_index = i;
2270
                                if (pkt.flags & PKT_FLAG_KEY) {
2271
                                    c->got_key_frame |= 1 << i;
2272
                                }
2273
                                /* See if we have all the key frames, then 
2274
                                 * we start to send. This logic is not quite
2275
                                 * right, but it works for the case of a 
2276
                                 * single video stream with one or more
2277
                                 * audio streams (for which every frame is 
2278
                                 * typically a key frame). 
2279
                                 */
2280
                                if (!c->stream->send_on_key || 
2281
                                    ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2282
                                    goto send_it;
2283
                                }
2284
                            }
2285
                        }
2286
                    } else {
2287
                        AVCodecContext *codec;
2288
                        
2289
                    send_it:
2290
                        /* specific handling for RTP: we use several
2291
                           output stream (one for each RTP
2292
                           connection). XXX: need more abstract handling */
2293
                        if (c->is_packetized) {
2294
                            c->packet_stream_index = pkt.stream_index;
2295
                            ctx = c->rtp_ctx[c->packet_stream_index];
2296
                            if(!ctx) {
2297
                              av_free_packet(&pkt);
2298
                              break;
2299
                            }
2300
                            codec = &ctx->streams[0]->codec;
2301
                            /* only one stream per RTP connection */
2302
                            pkt.stream_index = 0;
2303
                        } else {
2304
                            ctx = &c->fmt_ctx;
2305
                            /* Fudge here */
2306
                            codec = &ctx->streams[pkt.stream_index]->codec;
2307
                        }
2308
                        
2309
                        codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2310
                        
2311
#ifdef PJSG
2312
                        if (codec->codec_type == CODEC_TYPE_AUDIO) {
2313
                            codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2314
                            /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2315
                        }
2316
#endif
2317
                        
2318
                        if (c->is_packetized) {
2319
                            int max_packet_size;
2320
                            if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2321
                                max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2322
                            else
2323
                                max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2324
                            ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2325
                            c->packet_byte_count = 0;
2326
                            c->packet_start_time_us = av_gettime();
2327
                        } else {
2328
                            ret = url_open_dyn_buf(&ctx->pb);
2329
                        }
2330
                        if (ret < 0) {
2331
                            /* XXX: potential leak */
2332
                            return -1;
2333
                        }
2334
                        if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2335
                            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2336
                        }
2337
                        
2338
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2339
                        c->buffer_ptr = c->pb_buffer;
2340
                        c->buffer_end = c->pb_buffer + len;
2341
                        
2342
                        codec->frame_number++;
2343
                    }
2344
#ifndef AV_READ_FRAME
2345
                    av_free_packet(&pkt);
2346
#endif
2347
                }
2348
            }
2349
        }
2350
        break;
2351
    default:
2352
    case HTTPSTATE_SEND_DATA_TRAILER:
2353
        /* last packet test ? */
2354
        if (c->last_packet_sent || c->is_packetized)
2355
            return -1;
2356
        ctx = &c->fmt_ctx;
2357
        /* prepare header */
2358
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2359
            /* XXX: potential leak */
2360
            return -1;
2361
        }
2362
        av_write_trailer(ctx);
2363
        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2364
        c->buffer_ptr = c->pb_buffer;
2365
        c->buffer_end = c->pb_buffer + len;
2366

    
2367
        c->last_packet_sent = 1;
2368
        break;
2369
    }
2370
    return 0;
2371
}
2372

    
2373
/* in bit/s */
2374
#define SHORT_TERM_BANDWIDTH 8000000
2375

    
2376
/* should convert the format at the same time */
2377
/* send data starting at c->buffer_ptr to the output connection
2378
   (either UDP or TCP connection) */
2379
static int http_send_data(HTTPContext *c)
2380
{
2381
    int len, ret, dt;
2382

    
2383
    for(;;) {
2384
        if (c->buffer_ptr >= c->buffer_end) {
2385
            ret = http_prepare_data(c);
2386
            if (ret < 0)
2387
                return -1;
2388
            else if (ret != 0) {
2389
                /* state change requested */
2390
                break;
2391
            }
2392
        } else {
2393
            if (c->is_packetized) {
2394
                /* RTP data output */
2395
                len = c->buffer_end - c->buffer_ptr;
2396
                if (len < 4) {
2397
                    /* fail safe - should never happen */
2398
                fail1:
2399
                    c->buffer_ptr = c->buffer_end;
2400
                    return 0;
2401
                }
2402
                len = (c->buffer_ptr[0] << 24) |
2403
                    (c->buffer_ptr[1] << 16) |
2404
                    (c->buffer_ptr[2] << 8) |
2405
                    (c->buffer_ptr[3]);
2406
                if (len > (c->buffer_end - c->buffer_ptr))
2407
                    goto fail1;
2408
            
2409
                if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2410
                    /* RTP packets are sent inside the RTSP TCP connection */
2411
                    ByteIOContext pb1, *pb = &pb1;
2412
                    int interleaved_index, size;
2413
                    uint8_t header[4];
2414
                    HTTPContext *rtsp_c;
2415
                    
2416
                    rtsp_c = c->rtsp_c;
2417
                    /* if no RTSP connection left, error */
2418
                    if (!rtsp_c)
2419
                        return -1;
2420
                    /* if already sending something, then wait. */
2421
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2422
                        break;
2423
                    }
2424
                    if (url_open_dyn_buf(pb) < 0)
2425
                        goto fail1;
2426
                    interleaved_index = c->packet_stream_index * 2;
2427
                    /* RTCP packets are sent at odd indexes */
2428
                    if (c->buffer_ptr[1] == 200)
2429
                        interleaved_index++;
2430
                    /* write RTSP TCP header */
2431
                    header[0] = '$';
2432
                    header[1] = interleaved_index;
2433
                    header[2] = len >> 8;
2434
                    header[3] = len;
2435
                    put_buffer(pb, header, 4);
2436
                    /* write RTP packet data */
2437
                    c->buffer_ptr += 4;
2438
                    put_buffer(pb, c->buffer_ptr, len);
2439
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2440
                    /* prepare asynchronous TCP sending */
2441
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2442
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2443
                    rtsp_c->state = RTSPSTATE_SEND_PACKET;
2444
                } else {
2445
                    /* send RTP packet directly in UDP */
2446

    
2447
                    /* short term bandwidth limitation */
2448
                    dt = av_gettime() - c->packet_start_time_us;
2449
                    if (dt < 1)
2450
                        dt = 1;
2451
                    
2452
                    if ((c->packet_byte_count + len) * (int64_t)1000000 >= 
2453
                        (SHORT_TERM_BANDWIDTH / 8) * (int64_t)dt) {
2454
                        /* bandwidth overflow : wait at most one tick and retry */
2455
                        c->state = HTTPSTATE_WAIT_SHORT;
2456
                        return 0;
2457
                    }
2458

    
2459
                    c->buffer_ptr += 4;
2460
                    url_write(c->rtp_handles[c->packet_stream_index], 
2461
                              c->buffer_ptr, len);
2462
                }
2463
                c->buffer_ptr += len;
2464
                c->packet_byte_count += len;
2465
            } else {
2466
                /* TCP data output */
2467
                len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2468
                if (len < 0) {
2469
                    if (errno != EAGAIN && errno != EINTR) {
2470
                        /* error : close connection */
2471
                        return -1;
2472
                    } else {
2473
                        return 0;
2474
                    }
2475
                } else {
2476
                    c->buffer_ptr += len;
2477
                }
2478
            }
2479
            c->data_count += len;
2480
            update_datarate(&c->datarate, c->data_count);
2481
            if (c->stream)
2482
                c->stream->bytes_served += len;
2483
            break;
2484
        }
2485
    } /* for(;;) */
2486
    return 0;
2487
}
2488

    
2489
static int http_start_receive_data(HTTPContext *c)
2490
{
2491
    int fd;
2492

    
2493
    if (c->stream->feed_opened)
2494
        return -1;
2495

    
2496
    /* Don't permit writing to this one */
2497
    if (c->stream->readonly)
2498
        return -1;
2499

    
2500
    /* open feed */
2501
    fd = open(c->stream->feed_filename, O_RDWR);
2502
    if (fd < 0)
2503
        return -1;
2504
    c->feed_fd = fd;
2505
    
2506
    c->stream->feed_write_index = ffm_read_write_index(fd);
2507
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2508
    lseek(fd, 0, SEEK_SET);
2509

    
2510
    /* init buffer input */
2511
    c->buffer_ptr = c->buffer;
2512
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2513
    c->stream->feed_opened = 1;
2514
    return 0;
2515
}
2516
    
2517
static int http_receive_data(HTTPContext *c)
2518
{
2519
    HTTPContext *c1;
2520

    
2521
    if (c->buffer_end > c->buffer_ptr) {
2522
        int len;
2523

    
2524
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2525
        if (len < 0) {
2526
            if (errno != EAGAIN && errno != EINTR) {
2527
                /* error : close connection */
2528
                goto fail;
2529
            }
2530
        } else if (len == 0) {
2531
            /* end of connection : close it */
2532
            goto fail;
2533
        } else {
2534
            c->buffer_ptr += len;
2535
            c->data_count += len;
2536
            update_datarate(&c->datarate, c->data_count);
2537
        }
2538
    }
2539

    
2540
    if (c->buffer_ptr >= c->buffer_end) {
2541
        FFStream *feed = c->stream;
2542
        /* a packet has been received : write it in the store, except
2543
           if header */
2544
        if (c->data_count > FFM_PACKET_SIZE) {
2545
            
2546
            //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2547
            /* XXX: use llseek or url_seek */
2548
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2549
            write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2550
            
2551
            feed->feed_write_index += FFM_PACKET_SIZE;
2552
            /* update file size */
2553
            if (feed->feed_write_index > c->stream->feed_size)
2554
                feed->feed_size = feed->feed_write_index;
2555

    
2556
            /* handle wrap around if max file size reached */
2557
            if (feed->feed_write_index >= c->stream->feed_max_size)
2558
                feed->feed_write_index = FFM_PACKET_SIZE;
2559

    
2560
            /* write index */
2561
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2562

    
2563
            /* wake up any waiting connections */
2564
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2565
                if (c1->state == HTTPSTATE_WAIT_FEED && 
2566
                    c1->stream->feed == c->stream->feed) {
2567
                    c1->state = HTTPSTATE_SEND_DATA;
2568
                }
2569
            }
2570
        } else {
2571
            /* We have a header in our hands that contains useful data */
2572
            AVFormatContext s;
2573
            AVInputFormat *fmt_in;
2574
            ByteIOContext *pb = &s.pb;
2575
            int i;
2576

    
2577
            memset(&s, 0, sizeof(s));
2578

    
2579
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2580
            pb->buf_end = c->buffer_end;        /* ?? */
2581
            pb->is_streamed = 1;
2582

    
2583
            /* use feed output format name to find corresponding input format */
2584
            fmt_in = av_find_input_format(feed->fmt->name);
2585
            if (!fmt_in)
2586
                goto fail;
2587

    
2588
            if (fmt_in->priv_data_size > 0) {
2589
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2590
                if (!s.priv_data)
2591
                    goto fail;
2592
            } else
2593
                s.priv_data = NULL;
2594

    
2595
            if (fmt_in->read_header(&s, 0) < 0) {
2596
                av_freep(&s.priv_data);
2597
                goto fail;
2598
            }
2599

    
2600
            /* Now we have the actual streams */
2601
            if (s.nb_streams != feed->nb_streams) {
2602
                av_freep(&s.priv_data);
2603
                goto fail;
2604
            }
2605
            for (i = 0; i < s.nb_streams; i++) {
2606
                memcpy(&feed->streams[i]->codec, 
2607
                       &s.streams[i]->codec, sizeof(AVCodecContext));
2608
            } 
2609
            av_freep(&s.priv_data);
2610
        }
2611
        c->buffer_ptr = c->buffer;
2612
    }
2613

    
2614
    return 0;
2615
 fail:
2616
    c->stream->feed_opened = 0;
2617
    close(c->feed_fd);
2618
    return -1;
2619
}
2620

    
2621
/********************************************************************/
2622
/* RTSP handling */
2623

    
2624
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2625
{
2626
    const char *str;
2627
    time_t ti;
2628
    char *p;
2629
    char buf2[32];
2630

    
2631
    switch(error_number) {
2632
#define DEF(n, c, s) case c: str = s; break; 
2633
#include "rtspcodes.h"
2634
#undef DEF
2635
    default:
2636
        str = "Unknown Error";
2637
        break;
2638
    }
2639
     
2640
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2641
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2642

    
2643
    /* output GMT time */
2644
    ti = time(NULL);
2645
    p = ctime(&ti);
2646
    strcpy(buf2, p);
2647
    p = buf2 + strlen(p) - 1;
2648
    if (*p == '\n')
2649
        *p = '\0';
2650
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2651
}
2652

    
2653
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2654
{
2655
    rtsp_reply_header(c, error_number);
2656
    url_fprintf(c->pb, "\r\n");
2657
}
2658

    
2659
static int rtsp_parse_request(HTTPContext *c)
2660
{
2661
    const char *p, *p1, *p2;
2662
    char cmd[32];
2663
    char url[1024];
2664
    char protocol[32];
2665
    char line[1024];
2666
    ByteIOContext pb1;
2667
    int len;
2668
    RTSPHeader header1, *header = &header1;
2669
    
2670
    c->buffer_ptr[0] = '\0';
2671
    p = c->buffer;
2672
    
2673
    get_word(cmd, sizeof(cmd), &p);
2674
    get_word(url, sizeof(url), &p);
2675
    get_word(protocol, sizeof(protocol), &p);
2676

    
2677
    pstrcpy(c->method, sizeof(c->method), cmd);
2678
    pstrcpy(c->url, sizeof(c->url), url);
2679
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2680

    
2681
    c->pb = &pb1;
2682
    if (url_open_dyn_buf(c->pb) < 0) {
2683
        /* XXX: cannot do more */
2684
        c->pb = NULL; /* safety */
2685
        return -1;
2686
    }
2687

    
2688
    /* check version name */
2689
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2690
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2691
        goto the_end;
2692
    }
2693

    
2694
    /* parse each header line */
2695
    memset(header, 0, sizeof(RTSPHeader));
2696
    /* skip to next line */
2697
    while (*p != '\n' && *p != '\0')
2698
        p++;
2699
    if (*p == '\n')
2700
        p++;
2701
    while (*p != '\0') {
2702
        p1 = strchr(p, '\n');
2703
        if (!p1)
2704
            break;
2705
        p2 = p1;
2706
        if (p2 > p && p2[-1] == '\r')
2707
            p2--;
2708
        /* skip empty line */
2709
        if (p2 == p)
2710
            break;
2711
        len = p2 - p;
2712
        if (len > sizeof(line) - 1)
2713
            len = sizeof(line) - 1;
2714
        memcpy(line, p, len);
2715
        line[len] = '\0';
2716
        rtsp_parse_line(header, line);
2717
        p = p1 + 1;
2718
    }
2719

    
2720
    /* handle sequence number */
2721
    c->seq = header->seq;
2722

    
2723
    if (!strcmp(cmd, "DESCRIBE")) {
2724
        rtsp_cmd_describe(c, url);
2725
    } else if (!strcmp(cmd, "OPTIONS")) {
2726
        rtsp_cmd_options(c, url);
2727
    } else if (!strcmp(cmd, "SETUP")) {
2728
        rtsp_cmd_setup(c, url, header);
2729
    } else if (!strcmp(cmd, "PLAY")) {
2730
        rtsp_cmd_play(c, url, header);
2731
    } else if (!strcmp(cmd, "PAUSE")) {
2732
        rtsp_cmd_pause(c, url, header);
2733
    } else if (!strcmp(cmd, "TEARDOWN")) {
2734
        rtsp_cmd_teardown(c, url, header);
2735
    } else {
2736
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2737
    }
2738
 the_end:
2739
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2740
    c->pb = NULL; /* safety */
2741
    if (len < 0) {
2742
        /* XXX: cannot do more */
2743
        return -1;
2744
    }
2745
    c->buffer_ptr = c->pb_buffer;
2746
    c->buffer_end = c->pb_buffer + len;
2747
    c->state = RTSPSTATE_SEND_REPLY;
2748
    return 0;
2749
}
2750

    
2751
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2752
   AVFormatContext */
2753
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
2754
                                   struct in_addr my_ip)
2755
{
2756
    ByteIOContext pb1, *pb = &pb1;
2757
    int i, payload_type, port, private_payload_type, j;
2758
    const char *ipstr, *title, *mediatype;
2759
    AVStream *st;
2760
    
2761
    if (url_open_dyn_buf(pb) < 0)
2762
        return -1;
2763
    
2764
    /* general media info */
2765

    
2766
    url_fprintf(pb, "v=0\n");
2767
    ipstr = inet_ntoa(my_ip);
2768
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2769
    title = stream->title;
2770
    if (title[0] == '\0')
2771
        title = "No Title";
2772
    url_fprintf(pb, "s=%s\n", title);
2773
    if (stream->comment[0] != '\0')
2774
        url_fprintf(pb, "i=%s\n", stream->comment);
2775
    if (stream->is_multicast) {
2776
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2777
    }
2778
    /* for each stream, we output the necessary info */
2779
    private_payload_type = 96;
2780
    for(i = 0; i < stream->nb_streams; i++) {
2781
        st = stream->streams[i];
2782
        switch(st->codec.codec_type) {
2783
        case CODEC_TYPE_AUDIO:
2784
            mediatype = "audio";
2785
            break;
2786
        case CODEC_TYPE_VIDEO:
2787
            mediatype = "video";
2788
            break;
2789
        default:
2790
            mediatype = "application";
2791
            break;
2792
        }
2793
        /* NOTE: the port indication is not correct in case of
2794
           unicast. It is not an issue because RTSP gives it */
2795
        payload_type = rtp_get_payload_type(&st->codec);
2796
        if (payload_type < 0)
2797
            payload_type = private_payload_type++;
2798
        if (stream->is_multicast) {
2799
            port = stream->multicast_port + 2 * i;
2800
        } else {
2801
            port = 0;
2802
        }
2803
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2804
                    mediatype, port, payload_type);
2805
        if (payload_type >= 96) {
2806
            /* for private payload type, we need to give more info */
2807
            switch(st->codec.codec_id) {
2808
            case CODEC_ID_MPEG4:
2809
                {
2810
                    uint8_t *data;
2811
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n", 
2812
                                payload_type, 90000);
2813
                    /* we must also add the mpeg4 header */
2814
                    data = st->codec.extradata;
2815
                    if (data) {
2816
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2817
                        for(j=0;j<st->codec.extradata_size;j++) {
2818
                            url_fprintf(pb, "%02x", data[j]);
2819
                        }
2820
                        url_fprintf(pb, "\n");
2821
                    }
2822
                }
2823
                break;
2824
            default:
2825
                /* XXX: add other codecs ? */
2826
                goto fail;
2827
            }
2828
        }
2829
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2830
    }
2831
    return url_close_dyn_buf(pb, pbuffer);
2832
 fail:
2833
    url_close_dyn_buf(pb, pbuffer);
2834
    av_free(*pbuffer);
2835
    return -1;
2836
}
2837

    
2838
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2839
{
2840
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2841
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2842
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2843
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2844
    url_fprintf(c->pb, "\r\n");
2845
}
2846

    
2847
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2848
{
2849
    FFStream *stream;
2850
    char path1[1024];
2851
    const char *path;
2852
    uint8_t *content;
2853
    int content_length, len;
2854
    struct sockaddr_in my_addr;
2855
    
2856
    /* find which url is asked */
2857
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2858
    path = path1;
2859
    if (*path == '/')
2860
        path++;
2861

    
2862
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2863
        if (!stream->is_feed && stream->fmt == &rtp_mux &&
2864
            !strcmp(path, stream->filename)) {
2865
            goto found;
2866
        }
2867
    }
2868
    /* no stream found */
2869
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2870
    return;
2871

    
2872
 found:
2873
    /* prepare the media description in sdp format */
2874

    
2875
    /* get the host IP */
2876
    len = sizeof(my_addr);
2877
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2878
    
2879
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2880
    if (content_length < 0) {
2881
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2882
        return;
2883
    }
2884
    rtsp_reply_header(c, RTSP_STATUS_OK);
2885
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2886
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2887
    url_fprintf(c->pb, "\r\n");
2888
    put_buffer(c->pb, content, content_length);
2889
}
2890

    
2891
static HTTPContext *find_rtp_session(const char *session_id)
2892
{
2893
    HTTPContext *c;
2894

    
2895
    if (session_id[0] == '\0')
2896
        return NULL;
2897

    
2898
    for(c = first_http_ctx; c != NULL; c = c->next) {
2899
        if (!strcmp(c->session_id, session_id))
2900
            return c;
2901
    }
2902
    return NULL;
2903
}
2904

    
2905
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2906
{
2907
    RTSPTransportField *th;
2908
    int i;
2909

    
2910
    for(i=0;i<h->nb_transports;i++) {
2911
        th = &h->transports[i];
2912
        if (th->protocol == protocol)
2913
            return th;
2914
    }
2915
    return NULL;
2916
}
2917

    
2918
static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2919
                           RTSPHeader *h)
2920
{
2921
    FFStream *stream;
2922
    int stream_index, port;
2923
    char buf[1024];
2924
    char path1[1024];
2925
    const char *path;
2926
    HTTPContext *rtp_c;
2927
    RTSPTransportField *th;
2928
    struct sockaddr_in dest_addr;
2929
    RTSPActionServerSetup setup;
2930
    
2931
    /* find which url is asked */
2932
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2933
    path = path1;
2934
    if (*path == '/')
2935
        path++;
2936

    
2937
    /* now check each stream */
2938
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2939
        if (!stream->is_feed && stream->fmt == &rtp_mux) {
2940
            /* accept aggregate filenames only if single stream */
2941
            if (!strcmp(path, stream->filename)) {
2942
                if (stream->nb_streams != 1) {
2943
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2944
                    return;
2945
                }
2946
                stream_index = 0;
2947
                goto found;
2948
            }
2949
                
2950
            for(stream_index = 0; stream_index < stream->nb_streams;
2951
                stream_index++) {
2952
                snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2953
                         stream->filename, stream_index);
2954
                if (!strcmp(path, buf))
2955
                    goto found;
2956
            }
2957
        }
2958
    }
2959
    /* no stream found */
2960
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2961
    return;
2962
 found:
2963

    
2964
    /* generate session id if needed */
2965
    if (h->session_id[0] == '\0') {
2966
        snprintf(h->session_id, sizeof(h->session_id), 
2967
                 "%08x%08x", (int)random(), (int)random());
2968
    }
2969

    
2970
    /* find rtp session, and create it if none found */
2971
    rtp_c = find_rtp_session(h->session_id);
2972
    if (!rtp_c) {
2973
        /* always prefer UDP */
2974
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2975
        if (!th) {
2976
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2977
            if (!th) {
2978
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2979
                return;
2980
            }
2981
        }
2982

    
2983
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2984
                                   th->protocol);
2985
        if (!rtp_c) {
2986
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2987
            return;
2988
        }
2989

    
2990
        /* open input stream */
2991
        if (open_input_stream(rtp_c, "") < 0) {
2992
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2993
            return;
2994
        }
2995
    }
2996
    
2997
    /* test if stream is OK (test needed because several SETUP needs
2998
       to be done for a given file) */
2999
    if (rtp_c->stream != stream) {
3000
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3001
        return;
3002
    }
3003
    
3004
    /* test if stream is already set up */
3005
    if (rtp_c->rtp_ctx[stream_index]) {
3006
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3007
        return;
3008
    }
3009

    
3010
    /* check transport */
3011
    th = find_transport(h, rtp_c->rtp_protocol);
3012
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
3013
                th->client_port_min <= 0)) {
3014
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3015
        return;
3016
    }
3017

    
3018
    /* setup default options */
3019
    setup.transport_option[0] = '\0';
3020
    dest_addr = rtp_c->from_addr;
3021
    dest_addr.sin_port = htons(th->client_port_min);
3022
    
3023
    /* add transport option if needed */
3024
    if (ff_rtsp_callback) {
3025
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
3026
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
3027
                             (char *)&setup, sizeof(setup),
3028
                             stream->rtsp_option) < 0) {
3029
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3030
            return;
3031
        }
3032
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
3033
    }
3034
    
3035
    /* setup stream */
3036
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3037
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3038
        return;
3039
    }
3040

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

    
3046
    switch(rtp_c->rtp_protocol) {
3047
    case RTSP_PROTOCOL_RTP_UDP:
3048
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
3049
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3050
                    "client_port=%d-%d;server_port=%d-%d",
3051
                    th->client_port_min, th->client_port_min + 1,
3052
                    port, port + 1);
3053
        break;
3054
    case RTSP_PROTOCOL_RTP_TCP:
3055
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3056
                    stream_index * 2, stream_index * 2 + 1);
3057
        break;
3058
    default:
3059
        break;
3060
    }
3061
    if (setup.transport_option[0] != '\0') {
3062
        url_fprintf(c->pb, ";%s", setup.transport_option);
3063
    }
3064
    url_fprintf(c->pb, "\r\n");
3065
    
3066

    
3067
    url_fprintf(c->pb, "\r\n");
3068
}
3069

    
3070

    
3071
/* find an rtp connection by using the session ID. Check consistency
3072
   with filename */
3073
static HTTPContext *find_rtp_session_with_url(const char *url, 
3074
                                              const char *session_id)
3075
{
3076
    HTTPContext *rtp_c;
3077
    char path1[1024];
3078
    const char *path;
3079
    char buf[1024];
3080
    int s;
3081

    
3082
    rtp_c = find_rtp_session(session_id);
3083
    if (!rtp_c)
3084
        return NULL;
3085

    
3086
    /* find which url is asked */
3087
    url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3088
    path = path1;
3089
    if (*path == '/')
3090
        path++;
3091
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3092
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3093
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3094
        rtp_c->stream->filename, s);
3095
      if(!strncmp(path, buf, sizeof(buf))) {
3096
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3097
        return rtp_c;
3098
      }
3099
    }
3100
    return NULL;
3101
}
3102

    
3103
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3104
{
3105
    HTTPContext *rtp_c;
3106

    
3107
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3108
    if (!rtp_c) {
3109
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3110
        return;
3111
    }
3112
    
3113
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3114
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3115
        rtp_c->state != HTTPSTATE_READY) {
3116
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3117
        return;
3118
    }
3119

    
3120
    rtp_c->state = HTTPSTATE_SEND_DATA;
3121
    
3122
    /* now everything is OK, so we can send the connection parameters */
3123
    rtsp_reply_header(c, RTSP_STATUS_OK);
3124
    /* session ID */
3125
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3126
    url_fprintf(c->pb, "\r\n");
3127
}
3128

    
3129
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3130
{
3131
    HTTPContext *rtp_c;
3132

    
3133
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3134
    if (!rtp_c) {
3135
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3136
        return;
3137
    }
3138
    
3139
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3140
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3141
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3142
        return;
3143
    }
3144
    
3145
    rtp_c->state = HTTPSTATE_READY;
3146
    rtp_c->first_pts = AV_NOPTS_VALUE;
3147
    /* now everything is OK, so we can send the connection parameters */
3148
    rtsp_reply_header(c, RTSP_STATUS_OK);
3149
    /* session ID */
3150
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3151
    url_fprintf(c->pb, "\r\n");
3152
}
3153

    
3154
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3155
{
3156
    HTTPContext *rtp_c;
3157

    
3158
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3159
    if (!rtp_c) {
3160
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3161
        return;
3162
    }
3163
    
3164
    /* abort the session */
3165
    close_connection(rtp_c);
3166

    
3167
    if (ff_rtsp_callback) {
3168
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
3169
                         NULL, 0,
3170
                         rtp_c->stream->rtsp_option);
3171
    }
3172

    
3173
    /* now everything is OK, so we can send the connection parameters */
3174
    rtsp_reply_header(c, RTSP_STATUS_OK);
3175
    /* session ID */
3176
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3177
    url_fprintf(c->pb, "\r\n");
3178
}
3179

    
3180

    
3181
/********************************************************************/
3182
/* RTP handling */
3183

    
3184
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
3185
                                       FFStream *stream, const char *session_id,
3186
                                       enum RTSPProtocol rtp_protocol)
3187
{
3188
    HTTPContext *c = NULL;
3189
    const char *proto_str;
3190
    
3191
    /* XXX: should output a warning page when coming
3192
       close to the connection limit */
3193
    if (nb_connections >= nb_max_connections)
3194
        goto fail;
3195
    
3196
    /* add a new connection */
3197
    c = av_mallocz(sizeof(HTTPContext));
3198
    if (!c)
3199
        goto fail;
3200
    
3201
    c->fd = -1;
3202
    c->poll_entry = NULL;
3203
    c->from_addr = *from_addr;
3204
    c->buffer_size = IOBUFFER_INIT_SIZE;
3205
    c->buffer = av_malloc(c->buffer_size);
3206
    if (!c->buffer)
3207
        goto fail;
3208
    nb_connections++;
3209
    c->stream = stream;
3210
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3211
    c->state = HTTPSTATE_READY;
3212
    c->is_packetized = 1;
3213
    c->rtp_protocol = rtp_protocol;
3214

    
3215
    /* protocol is shown in statistics */
3216
    switch(c->rtp_protocol) {
3217
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3218
        proto_str = "MCAST";
3219
        break;
3220
    case RTSP_PROTOCOL_RTP_UDP:
3221
        proto_str = "UDP";
3222
        break;
3223
    case RTSP_PROTOCOL_RTP_TCP:
3224
        proto_str = "TCP";
3225
        break;
3226
    default:
3227
        proto_str = "???";
3228
        break;
3229
    }
3230
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3231
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3232

    
3233
    current_bandwidth += stream->bandwidth;
3234

    
3235
    c->next = first_http_ctx;
3236
    first_http_ctx = c;
3237
    return c;
3238
        
3239
 fail:
3240
    if (c) {
3241
        av_free(c->buffer);
3242
        av_free(c);
3243
    }
3244
    return NULL;
3245
}
3246

    
3247
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3248
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3249
   used. */
3250
static int rtp_new_av_stream(HTTPContext *c, 
3251
                             int stream_index, struct sockaddr_in *dest_addr,
3252
                             HTTPContext *rtsp_c)
3253
{
3254
    AVFormatContext *ctx;
3255
    AVStream *st;
3256
    char *ipaddr;
3257
    URLContext *h;
3258
    uint8_t *dummy_buf;
3259
    char buf2[32];
3260
    int max_packet_size;
3261
    
3262
    /* now we can open the relevant output stream */
3263
    ctx = av_mallocz(sizeof(AVFormatContext));
3264
    if (!ctx)
3265
        return -1;
3266
    ctx->oformat = &rtp_mux;
3267

    
3268
    st = av_mallocz(sizeof(AVStream));
3269
    if (!st)
3270
        goto fail;
3271
    ctx->nb_streams = 1;
3272
    ctx->streams[0] = st;
3273

    
3274
    if (!c->stream->feed || 
3275
        c->stream->feed == c->stream) {
3276
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3277
    } else {
3278
        memcpy(st, 
3279
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3280
               sizeof(AVStream));
3281
    }
3282
    
3283
    /* build destination RTP address */
3284
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3285

    
3286
    switch(c->rtp_protocol) {
3287
    case RTSP_PROTOCOL_RTP_UDP:
3288
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3289
        /* RTP/UDP case */
3290
        
3291
        /* XXX: also pass as parameter to function ? */
3292
        if (c->stream->is_multicast) {
3293
            int ttl;
3294
            ttl = c->stream->multicast_ttl;
3295
            if (!ttl)
3296
                ttl = 16;
3297
            snprintf(ctx->filename, sizeof(ctx->filename),
3298
                     "rtp://%s:%d?multicast=1&ttl=%d", 
3299
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3300
        } else {
3301
            snprintf(ctx->filename, sizeof(ctx->filename),
3302
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3303
        }
3304

    
3305
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3306
            goto fail;
3307
        c->rtp_handles[stream_index] = h;
3308
        max_packet_size = url_get_max_packet_size(h);
3309
        break;
3310
    case RTSP_PROTOCOL_RTP_TCP:
3311
        /* RTP/TCP case */
3312
        c->rtsp_c = rtsp_c;
3313
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3314
        break;
3315
    default:
3316
        goto fail;
3317
    }
3318

    
3319
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3320
             ipaddr, ntohs(dest_addr->sin_port), 
3321
             ctime1(buf2), 
3322
             c->stream->filename, stream_index, c->protocol);
3323

    
3324
    /* normally, no packets should be output here, but the packet size may be checked */
3325
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3326
        /* XXX: close stream */
3327
        goto fail;
3328
    }
3329
    av_set_parameters(ctx, NULL);
3330
    if (av_write_header(ctx) < 0) {
3331
    fail:
3332
        if (h)
3333
            url_close(h);
3334
        av_free(ctx);
3335
        return -1;
3336
    }
3337
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3338
    av_free(dummy_buf);
3339
    
3340
    c->rtp_ctx[stream_index] = ctx;
3341
    return 0;
3342
}
3343

    
3344
/********************************************************************/
3345
/* ffserver initialization */
3346

    
3347
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3348
{
3349
    AVStream *fst;
3350

    
3351
    fst = av_mallocz(sizeof(AVStream));
3352
    if (!fst)
3353
        return NULL;
3354
    fst->priv_data = av_mallocz(sizeof(FeedData));
3355
    memcpy(&fst->codec, codec, sizeof(AVCodecContext));
3356
    fst->codec.coded_frame = &dummy_frame;
3357
    stream->streams[stream->nb_streams++] = fst;
3358
    return fst;
3359
}
3360

    
3361
/* return the stream number in the feed */
3362
static int add_av_stream(FFStream *feed, AVStream *st)
3363
{
3364
    AVStream *fst;
3365
    AVCodecContext *av, *av1;
3366
    int i;
3367

    
3368
    av = &st->codec;
3369
    for(i=0;i<feed->nb_streams;i++) {
3370
        st = feed->streams[i];
3371
        av1 = &st->codec;
3372
        if (av1->codec_id == av->codec_id &&
3373
            av1->codec_type == av->codec_type &&
3374
            av1->bit_rate == av->bit_rate) {
3375

    
3376
            switch(av->codec_type) {
3377
            case CODEC_TYPE_AUDIO:
3378
                if (av1->channels == av->channels &&
3379
                    av1->sample_rate == av->sample_rate)
3380
                    goto found;
3381
                break;
3382
            case CODEC_TYPE_VIDEO:
3383
                if (av1->width == av->width &&
3384
                    av1->height == av->height &&
3385
                    av1->frame_rate == av->frame_rate &&
3386
                    av1->frame_rate_base == av->frame_rate_base &&
3387
                    av1->gop_size == av->gop_size)
3388
                    goto found;
3389
                break;
3390
            default:
3391
                av_abort();
3392
            }
3393
        }
3394
    }
3395
    
3396
    fst = add_av_stream1(feed, av);
3397
    if (!fst)
3398
        return -1;
3399
    return feed->nb_streams - 1;
3400
 found:
3401
    return i;
3402
}
3403

    
3404
static void remove_stream(FFStream *stream)
3405
{
3406
    FFStream **ps;
3407
    ps = &first_stream;
3408
    while (*ps != NULL) {
3409
        if (*ps == stream) {
3410
            *ps = (*ps)->next;
3411
        } else {
3412
            ps = &(*ps)->next;
3413
        }
3414
    }
3415
}
3416

    
3417
/* specific mpeg4 handling : we extract the raw parameters */
3418
static void extract_mpeg4_header(AVFormatContext *infile)
3419
{
3420
    int mpeg4_count, i, size;
3421
    AVPacket pkt;
3422
    AVStream *st;
3423
    const uint8_t *p;
3424

    
3425
    mpeg4_count = 0;
3426
    for(i=0;i<infile->nb_streams;i++) {
3427
        st = infile->streams[i];
3428
        if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3429
            st->codec.extradata_size == 0) {
3430
            mpeg4_count++;
3431
        }
3432
    }
3433
    if (!mpeg4_count)
3434
        return;
3435

    
3436
    printf("MPEG4 without extra data: trying to find header\n");
3437
    while (mpeg4_count > 0) {
3438
        if (av_read_packet(infile, &pkt) < 0)
3439
            break;
3440
        st = infile->streams[pkt.stream_index];
3441
        if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3442
            st->codec.extradata_size == 0) {
3443
            av_freep(&st->codec.extradata);
3444
            /* fill extradata with the header */
3445
            /* XXX: we make hard suppositions here ! */
3446
            p = pkt.data;
3447
            while (p < pkt.data + pkt.size - 4) {
3448
                /* stop when vop header is found */
3449
                if (p[0] == 0x00 && p[1] == 0x00 && 
3450
                    p[2] == 0x01 && p[3] == 0xb6) {
3451
                    size = p - pkt.data;
3452
                    //                    av_hex_dump(pkt.data, size);
3453
                    st->codec.extradata = av_malloc(size);
3454
                    st->codec.extradata_size = size;
3455
                    memcpy(st->codec.extradata, pkt.data, size);
3456
                    break;
3457
                }
3458
                p++;
3459
            }
3460
            mpeg4_count--;
3461
        }
3462
        av_free_packet(&pkt);
3463
    }
3464
}
3465

    
3466
/* compute the needed AVStream for each file */
3467
static void build_file_streams(void)
3468
{
3469
    FFStream *stream, *stream_next;
3470
    AVFormatContext *infile;
3471
    int i;
3472

    
3473
    /* gather all streams */
3474
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3475
        stream_next = stream->next;
3476
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3477
            !stream->feed) {
3478
            /* the stream comes from a file */
3479
            /* try to open the file */
3480
            /* open stream */
3481
            if (av_open_input_file(&infile, stream->feed_filename, 
3482
                                   NULL, 0, NULL) < 0) {
3483
                http_log("%s not found", stream->feed_filename);
3484
                /* remove stream (no need to spend more time on it) */
3485
            fail:
3486
                remove_stream(stream);
3487
            } else {
3488
                /* find all the AVStreams inside and reference them in
3489
                   'stream' */
3490
                if (av_find_stream_info(infile) < 0) {
3491
                    http_log("Could not find codec parameters from '%s'", 
3492
                             stream->feed_filename);
3493
                    av_close_input_file(infile);
3494
                    goto fail;
3495
                }
3496
                extract_mpeg4_header(infile);
3497

    
3498
                for(i=0;i<infile->nb_streams;i++) {
3499
                    add_av_stream1(stream, &infile->streams[i]->codec);
3500
                }
3501
                av_close_input_file(infile);
3502
            }
3503
        }
3504
    }
3505
}
3506

    
3507
/* compute the needed AVStream for each feed */
3508
static void build_feed_streams(void)
3509
{
3510
    FFStream *stream, *feed;
3511
    int i;
3512

    
3513
    /* gather all streams */
3514
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3515
        feed = stream->feed;
3516
        if (feed) {
3517
            if (!stream->is_feed) {
3518
                /* we handle a stream coming from a feed */
3519
                for(i=0;i<stream->nb_streams;i++) {
3520
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3521
                }
3522
            }
3523
        }
3524
    }
3525

    
3526
    /* gather all streams */
3527
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3528
        feed = stream->feed;
3529
        if (feed) {
3530
            if (stream->is_feed) {
3531
                for(i=0;i<stream->nb_streams;i++) {
3532
                    stream->feed_streams[i] = i;
3533
                }
3534
            }
3535
        }
3536
    }
3537

    
3538
    /* create feed files if needed */
3539
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3540
        int fd;
3541

    
3542
        if (url_exist(feed->feed_filename)) {
3543
            /* See if it matches */
3544
            AVFormatContext *s;
3545
            int matches = 0;
3546

    
3547
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3548
                /* Now see if it matches */
3549
                if (s->nb_streams == feed->nb_streams) {
3550
                    matches = 1;
3551
                    for(i=0;i<s->nb_streams;i++) {
3552
                        AVStream *sf, *ss;
3553
                        sf = feed->streams[i];
3554
                        ss = s->streams[i];
3555

    
3556
                        if (sf->index != ss->index ||
3557
                            sf->id != ss->id) {
3558
                            printf("Index & Id do not match for stream %d\n", i);
3559
                            matches = 0;
3560
                        } else {
3561
                            AVCodecContext *ccf, *ccs;
3562

    
3563
                            ccf = &sf->codec;
3564
                            ccs = &ss->codec;
3565
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3566

    
3567
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3568
                                printf("Codecs do not match for stream %d\n", i);
3569
                                matches = 0;
3570
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3571
                                printf("Codec bitrates do not match for stream %d\n", i);
3572
                                matches = 0;
3573
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3574
                                if (CHECK_CODEC(frame_rate) ||
3575
                                    CHECK_CODEC(frame_rate_base) ||
3576
                                    CHECK_CODEC(width) ||
3577
                                    CHECK_CODEC(height)) {
3578
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3579
                                    matches = 0;
3580
                                }
3581
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3582
                                if (CHECK_CODEC(sample_rate) ||
3583
                                    CHECK_CODEC(channels) ||
3584
                                    CHECK_CODEC(frame_size)) {
3585
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3586
                                    matches = 0;
3587
                                }
3588
                            } else {
3589
                                printf("Unknown codec type\n");
3590
                                matches = 0;
3591
                            }
3592
                        }
3593
                        if (!matches) {
3594
                            break;
3595
                        }
3596
                    }
3597
                } else {
3598
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3599
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3600
                }
3601

    
3602
                av_close_input_file(s);
3603
            } else {
3604
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3605
                        feed->feed_filename);
3606
            }
3607
            if (!matches) {
3608
                if (feed->readonly) {
3609
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3610
                        feed->feed_filename);
3611
                    exit(1);
3612
                }
3613
                unlink(feed->feed_filename);
3614
            }
3615
        }
3616
        if (!url_exist(feed->feed_filename)) {
3617
            AVFormatContext s1, *s = &s1;
3618

    
3619
            if (feed->readonly) {
3620
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3621
                    feed->feed_filename);
3622
                exit(1);
3623
            }
3624

    
3625
            /* only write the header of the ffm file */
3626
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3627
                fprintf(stderr, "Could not open output feed file '%s'\n",
3628
                        feed->feed_filename);
3629
                exit(1);
3630
            }
3631
            s->oformat = feed->fmt;
3632
            s->nb_streams = feed->nb_streams;
3633
            for(i=0;i<s->nb_streams;i++) {
3634
                AVStream *st;
3635
                st = feed->streams[i];
3636
                s->streams[i] = st;
3637
            }
3638
            av_set_parameters(s, NULL);
3639
            av_write_header(s);
3640
            /* XXX: need better api */
3641
            av_freep(&s->priv_data);
3642
            url_fclose(&s->pb);
3643
        }
3644
        /* get feed size and write index */
3645
        fd = open(feed->feed_filename, O_RDONLY);
3646
        if (fd < 0) {
3647
            fprintf(stderr, "Could not open output feed file '%s'\n",
3648
                    feed->feed_filename);
3649
            exit(1);
3650
        }
3651

    
3652
        feed->feed_write_index = ffm_read_write_index(fd);
3653
        feed->feed_size = lseek(fd, 0, SEEK_END);
3654
        /* ensure that we do not wrap before the end of file */
3655
        if (feed->feed_max_size < feed->feed_size)
3656
            feed->feed_max_size = feed->feed_size;
3657

    
3658
        close(fd);
3659
    }
3660
}
3661

    
3662
/* compute the bandwidth used by each stream */
3663
static void compute_bandwidth(void)
3664
{
3665
    int bandwidth, i;
3666
    FFStream *stream;
3667
    
3668
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3669
        bandwidth = 0;
3670
        for(i=0;i<stream->nb_streams;i++) {
3671
            AVStream *st = stream->streams[i];
3672
            switch(st->codec.codec_type) {
3673
            case CODEC_TYPE_AUDIO:
3674
            case CODEC_TYPE_VIDEO:
3675
                bandwidth += st->codec.bit_rate;
3676
                break;
3677
            default:
3678
                break;
3679
            }
3680
        }
3681
        stream->bandwidth = (bandwidth + 999) / 1000;
3682
    }
3683
}
3684

    
3685
static void get_arg(char *buf, int buf_size, const char **pp)
3686
{
3687
    const char *p;
3688
    char *q;
3689
    int quote;
3690

    
3691
    p = *pp;
3692
    while (isspace(*p)) p++;
3693
    q = buf;
3694
    quote = 0;
3695
    if (*p == '\"' || *p == '\'')
3696
        quote = *p++;
3697
    for(;;) {
3698
        if (quote) {
3699
            if (*p == quote)
3700
                break;
3701
        } else {
3702
            if (isspace(*p))
3703
                break;
3704
        }
3705
        if (*p == '\0')
3706
            break;
3707
        if ((q - buf) < buf_size - 1)
3708
            *q++ = *p;
3709
        p++;
3710
    }
3711
    *q = '\0';
3712
    if (quote && *p == quote)
3713
        p++;
3714
    *pp = p;
3715
}
3716

    
3717
/* add a codec and set the default parameters */
3718
static void add_codec(FFStream *stream, AVCodecContext *av)
3719
{
3720
    AVStream *st;
3721

    
3722
    /* compute default parameters */
3723
    switch(av->codec_type) {
3724
    case CODEC_TYPE_AUDIO:
3725
        if (av->bit_rate == 0)
3726
            av->bit_rate = 64000;
3727
        if (av->sample_rate == 0)
3728
            av->sample_rate = 22050;
3729
        if (av->channels == 0)
3730
            av->channels = 1;
3731
        break;
3732
    case CODEC_TYPE_VIDEO:
3733
        if (av->bit_rate == 0)
3734
            av->bit_rate = 64000;
3735
        if (av->frame_rate == 0){
3736
            av->frame_rate = 5;
3737
            av->frame_rate_base = 1;
3738
        }
3739
        if (av->width == 0 || av->height == 0) {
3740
            av->width = 160;
3741
            av->height = 128;
3742
        }
3743
        /* Bitrate tolerance is less for streaming */
3744
        if (av->bit_rate_tolerance == 0)
3745
            av->bit_rate_tolerance = av->bit_rate / 4;
3746
        if (av->qmin == 0)
3747
            av->qmin = 3;
3748
        if (av->qmax == 0)
3749
            av->qmax = 31;
3750
        if (av->max_qdiff == 0)
3751
            av->max_qdiff = 3;
3752
        av->qcompress = 0.5;
3753
        av->qblur = 0.5;
3754

    
3755
        if (!av->rc_eq)
3756
            av->rc_eq = "tex^qComp";
3757
        if (!av->i_quant_factor)
3758
            av->i_quant_factor = -0.8;
3759
        if (!av->b_quant_factor)
3760
            av->b_quant_factor = 1.25;
3761
        if (!av->b_quant_offset)
3762
            av->b_quant_offset = 1.25;
3763
        if (!av->rc_min_rate)
3764
            av->rc_min_rate = av->bit_rate / 2;
3765
        if (!av->rc_max_rate)
3766
            av->rc_max_rate = av->bit_rate * 2;
3767

    
3768
        break;
3769
    default:
3770
        av_abort();
3771
    }
3772

    
3773
    st = av_mallocz(sizeof(AVStream));
3774
    if (!st)
3775
        return;
3776
    stream->streams[stream->nb_streams++] = st;
3777
    memcpy(&st->codec, av, sizeof(AVCodecContext));
3778
}
3779

    
3780
static int opt_audio_codec(const char *arg)
3781
{
3782
    AVCodec *p;
3783

    
3784
    p = first_avcodec;
3785
    while (p) {
3786
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3787
            break;
3788
        p = p->next;
3789
    }
3790
    if (p == NULL) {
3791
        return CODEC_ID_NONE;
3792
    }
3793

    
3794
    return p->id;
3795
}
3796

    
3797
static int opt_video_codec(const char *arg)
3798
{
3799
    AVCodec *p;
3800

    
3801
    p = first_avcodec;
3802
    while (p) {
3803
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3804
            break;
3805
        p = p->next;
3806
    }
3807
    if (p == NULL) {
3808
        return CODEC_ID_NONE;
3809
    }
3810

    
3811
    return p->id;
3812
}
3813

    
3814
/* simplistic plugin support */
3815

    
3816
#ifdef CONFIG_HAVE_DLOPEN
3817
void load_module(const char *filename)
3818
{
3819
    void *dll;
3820
    void (*init_func)(void);
3821
    dll = dlopen(filename, RTLD_NOW);
3822
    if (!dll) {
3823
        fprintf(stderr, "Could not load module '%s' - %s\n",
3824
                filename, dlerror());
3825
        return;
3826
    }
3827
    
3828
    init_func = dlsym(dll, "ffserver_module_init");
3829
    if (!init_func) {
3830
        fprintf(stderr, 
3831
                "%s: init function 'ffserver_module_init()' not found\n",
3832
                filename);
3833
        dlclose(dll);
3834
    }
3835

    
3836
    init_func();
3837
}
3838
#endif
3839

    
3840
static int parse_ffconfig(const char *filename)
3841
{
3842
    FILE *f;
3843
    char line[1024];
3844
    char cmd[64];
3845
    char arg[1024];
3846
    const char *p;
3847
    int val, errors, line_num;
3848
    FFStream **last_stream, *stream, *redirect;
3849
    FFStream **last_feed, *feed;
3850
    AVCodecContext audio_enc, video_enc;
3851
    int audio_id, video_id;
3852

    
3853
    f = fopen(filename, "r");
3854
    if (!f) {
3855
        perror(filename);
3856
        return -1;
3857
    }
3858
    
3859
    errors = 0;
3860
    line_num = 0;
3861
    first_stream = NULL;
3862
    last_stream = &first_stream;
3863
    first_feed = NULL;
3864
    last_feed = &first_feed;
3865
    stream = NULL;
3866
    feed = NULL;
3867
    redirect = NULL;
3868
    audio_id = CODEC_ID_NONE;
3869
    video_id = CODEC_ID_NONE;
3870
    for(;;) {
3871
        if (fgets(line, sizeof(line), f) == NULL)
3872
            break;
3873
        line_num++;
3874
        p = line;
3875
        while (isspace(*p)) 
3876
            p++;
3877
        if (*p == '\0' || *p == '#')
3878
            continue;
3879

    
3880
        get_arg(cmd, sizeof(cmd), &p);
3881
        
3882
        if (!strcasecmp(cmd, "Port")) {
3883
            get_arg(arg, sizeof(arg), &p);
3884
            my_http_addr.sin_port = htons (atoi(arg));
3885
        } else if (!strcasecmp(cmd, "BindAddress")) {
3886
            get_arg(arg, sizeof(arg), &p);
3887
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3888
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3889
                        filename, line_num, arg);
3890
                errors++;
3891
            }
3892
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3893
            ffserver_daemon = 0;
3894
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3895
            get_arg(arg, sizeof(arg), &p);
3896
            my_rtsp_addr.sin_port = htons (atoi(arg));
3897
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3898
            get_arg(arg, sizeof(arg), &p);
3899
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3900
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3901
                        filename, line_num, arg);
3902
                errors++;
3903
            }
3904
        } else if (!strcasecmp(cmd, "MaxClients")) {
3905
            get_arg(arg, sizeof(arg), &p);
3906
            val = atoi(arg);
3907
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3908
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3909
                        filename, line_num, arg);
3910
                errors++;
3911
            } else {
3912
                nb_max_connections = val;
3913
            }
3914
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3915
            get_arg(arg, sizeof(arg), &p);
3916
            val = atoi(arg);
3917
            if (val < 10 || val > 100000) {
3918
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3919
                        filename, line_num, arg);
3920
                errors++;
3921
            } else {
3922
                max_bandwidth = val;
3923
            }
3924
        } else if (!strcasecmp(cmd, "CustomLog")) {
3925
            get_arg(logfilename, sizeof(logfilename), &p);
3926
        } else if (!strcasecmp(cmd, "<Feed")) {
3927
            /*********************************************/
3928
            /* Feed related options */
3929
            char *q;
3930
            if (stream || feed) {
3931
                fprintf(stderr, "%s:%d: Already in a tag\n",
3932
                        filename, line_num);
3933
            } else {
3934
                feed = av_mallocz(sizeof(FFStream));
3935
                /* add in stream list */
3936
                *last_stream = feed;
3937
                last_stream = &feed->next;
3938
                /* add in feed list */
3939
                *last_feed = feed;
3940
                last_feed = &feed->next_feed;
3941
                
3942
                get_arg(feed->filename, sizeof(feed->filename), &p);
3943
                q = strrchr(feed->filename, '>');
3944
                if (*q)
3945
                    *q = '\0';
3946
                feed->fmt = guess_format("ffm", NULL, NULL);
3947
                /* defaut feed file */
3948
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3949
                         "/tmp/%s.ffm", feed->filename);
3950
                feed->feed_max_size = 5 * 1024 * 1024;
3951
                feed->is_feed = 1;
3952
                feed->feed = feed; /* self feeding :-) */
3953
            }
3954
        } else if (!strcasecmp(cmd, "Launch")) {
3955
            if (feed) {
3956
                int i;
3957

    
3958
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3959

    
3960
                feed->child_argv[0] = av_malloc(7);
3961
                strcpy(feed->child_argv[0], "ffmpeg");
3962

    
3963
                for (i = 1; i < 62; i++) {
3964
                    char argbuf[256];
3965

    
3966
                    get_arg(argbuf, sizeof(argbuf), &p);
3967
                    if (!argbuf[0])
3968
                        break;
3969

    
3970
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3971
                    strcpy(feed->child_argv[i], argbuf);
3972
                }
3973

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

    
3976
                snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3977
                    ntohs(my_http_addr.sin_port), feed->filename);
3978
            }
3979
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3980
            if (feed) {
3981
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3982
                feed->readonly = 1;
3983
            } else if (stream) {
3984
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3985
            }
3986
        } else if (!strcasecmp(cmd, "File")) {
3987
            if (feed) {
3988
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3989
            } else if (stream) {
3990
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3991
            }
3992
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3993
            if (feed) {
3994
                const char *p1;
3995
                double fsize;
3996

    
3997
                get_arg(arg, sizeof(arg), &p);
3998
                p1 = arg;
3999
                fsize = strtod(p1, (char **)&p1);
4000
                switch(toupper(*p1)) {
4001
                case 'K':
4002
                    fsize *= 1024;
4003
                    break;
4004
                case 'M':
4005
                    fsize *= 1024 * 1024;
4006
                    break;
4007
                case 'G':
4008
                    fsize *= 1024 * 1024 * 1024;
4009
                    break;
4010
                }
4011
                feed->feed_max_size = (int64_t)fsize;
4012
            }
4013
        } else if (!strcasecmp(cmd, "</Feed>")) {
4014
            if (!feed) {
4015
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
4016
                        filename, line_num);
4017
                errors++;
4018
#if 0
4019
            } else {
4020
                /* Make sure that we start out clean */
4021
                if (unlink(feed->feed_filename) < 0 
4022
                    && errno != ENOENT) {
4023
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
4024
                        filename, line_num, feed->feed_filename, strerror(errno));
4025
                    errors++;
4026
                }
4027
#endif
4028
            }
4029
            feed = NULL;
4030
        } else if (!strcasecmp(cmd, "<Stream")) {
4031
            /*********************************************/
4032
            /* Stream related options */
4033
            char *q;
4034
            if (stream || feed) {
4035
                fprintf(stderr, "%s:%d: Already in a tag\n",
4036
                        filename, line_num);
4037
            } else {
4038
                stream = av_mallocz(sizeof(FFStream));
4039
                *last_stream = stream;
4040
                last_stream = &stream->next;
4041

    
4042
                get_arg(stream->filename, sizeof(stream->filename), &p);
4043
                q = strrchr(stream->filename, '>');
4044
                if (*q)
4045
                    *q = '\0';
4046
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
4047
                memset(&audio_enc, 0, sizeof(AVCodecContext));
4048
                memset(&video_enc, 0, sizeof(AVCodecContext));
4049
                audio_id = CODEC_ID_NONE;
4050
                video_id = CODEC_ID_NONE;
4051
                if (stream->fmt) {
4052
                    audio_id = stream->fmt->audio_codec;
4053
                    video_id = stream->fmt->video_codec;
4054
                }
4055
            }
4056
        } else if (!strcasecmp(cmd, "Feed")) {
4057
            get_arg(arg, sizeof(arg), &p);
4058
            if (stream) {
4059
                FFStream *sfeed;
4060
                
4061
                sfeed = first_feed;
4062
                while (sfeed != NULL) {
4063
                    if (!strcmp(sfeed->filename, arg))
4064
                        break;
4065
                    sfeed = sfeed->next_feed;
4066
                }
4067
                if (!sfeed) {
4068
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4069
                            filename, line_num, arg);
4070
                } else {
4071
                    stream->feed = sfeed;
4072
                }
4073
            }
4074
        } else if (!strcasecmp(cmd, "Format")) {
4075
            get_arg(arg, sizeof(arg), &p);
4076
            if (!strcmp(arg, "status")) {
4077
                stream->stream_type = STREAM_TYPE_STATUS;
4078
                stream->fmt = NULL;
4079
            } else {
4080
                stream->stream_type = STREAM_TYPE_LIVE;
4081
                /* jpeg cannot be used here, so use single frame jpeg */
4082
                if (!strcmp(arg, "jpeg"))
4083
                    strcpy(arg, "singlejpeg");
4084
                stream->fmt = guess_stream_format(arg, NULL, NULL);
4085
                if (!stream->fmt) {
4086
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
4087
                            filename, line_num, arg);
4088
                    errors++;
4089
                }
4090
            }
4091
            if (stream->fmt) {
4092
                audio_id = stream->fmt->audio_codec;
4093
                video_id = stream->fmt->video_codec;
4094
            }
4095
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4096
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4097
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4098
            } else {
4099
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
4100
                            filename, line_num);
4101
                errors++;
4102
            }
4103
        } else if (!strcasecmp(cmd, "Author")) {
4104
            if (stream) {
4105
                get_arg(stream->author, sizeof(stream->author), &p);
4106
            }
4107
        } else if (!strcasecmp(cmd, "Comment")) {
4108
            if (stream) {
4109
                get_arg(stream->comment, sizeof(stream->comment), &p);
4110
            }
4111
        } else if (!strcasecmp(cmd, "Copyright")) {
4112
            if (stream) {
4113
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4114
            }
4115
        } else if (!strcasecmp(cmd, "Title")) {
4116
            if (stream) {
4117
                get_arg(stream->title, sizeof(stream->title), &p);
4118
            }
4119
        } else if (!strcasecmp(cmd, "Preroll")) {
4120
            get_arg(arg, sizeof(arg), &p);
4121
            if (stream) {
4122
                stream->prebuffer = atof(arg) * 1000;
4123
            }
4124
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4125
            if (stream) {
4126
                stream->send_on_key = 1;
4127
            }
4128
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4129
            get_arg(arg, sizeof(arg), &p);
4130
            audio_id = opt_audio_codec(arg);
4131
            if (audio_id == CODEC_ID_NONE) {
4132
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
4133
                        filename, line_num, arg);
4134
                errors++;
4135
            }
4136
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4137
            get_arg(arg, sizeof(arg), &p);
4138
            video_id = opt_video_codec(arg);
4139
            if (video_id == CODEC_ID_NONE) {
4140
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
4141
                        filename, line_num, arg);
4142
                errors++;
4143
            }
4144
        } else if (!strcasecmp(cmd, "MaxTime")) {
4145
            get_arg(arg, sizeof(arg), &p);
4146
            if (stream) {
4147
                stream->max_time = atof(arg) * 1000;
4148
            }
4149
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4150
            get_arg(arg, sizeof(arg), &p);
4151
            if (stream) {
4152
                audio_enc.bit_rate = atoi(arg) * 1000;
4153
            }
4154
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4155
            get_arg(arg, sizeof(arg), &p);
4156
            if (stream) {
4157
                audio_enc.channels = atoi(arg);
4158
            }
4159
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4160
            get_arg(arg, sizeof(arg), &p);
4161
            if (stream) {
4162
                audio_enc.sample_rate = atoi(arg);
4163
            }
4164
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4165
            get_arg(arg, sizeof(arg), &p);
4166
            if (stream) {
4167
//                audio_enc.quality = atof(arg) * 1000;
4168
            }
4169
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4170
            if (stream) {
4171
                int minrate, maxrate;
4172

    
4173
                get_arg(arg, sizeof(arg), &p);
4174

    
4175
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4176
                    video_enc.rc_min_rate = minrate * 1000;
4177
                    video_enc.rc_max_rate = maxrate * 1000;
4178
                } else {
4179
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
4180
                            filename, line_num, arg);
4181
                    errors++;
4182
                }
4183
            }
4184
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4185
            if (stream) {
4186
                get_arg(arg, sizeof(arg), &p);
4187
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4188
            }
4189
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4190
            get_arg(arg, sizeof(arg), &p);
4191
            if (stream) {
4192
                video_enc.bit_rate = atoi(arg) * 1000;
4193
            }
4194
        } else if (!strcasecmp(cmd, "VideoSize")) {
4195
            get_arg(arg, sizeof(arg), &p);
4196
            if (stream) {
4197
                parse_image_size(&video_enc.width, &video_enc.height, arg);
4198
                if ((video_enc.width % 16) != 0 ||
4199
                    (video_enc.height % 16) != 0) {
4200
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4201
                            filename, line_num);
4202
                    errors++;
4203
                }
4204
            }
4205
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4206
            get_arg(arg, sizeof(arg), &p);
4207
            if (stream) {
4208
                video_enc.frame_rate_base= DEFAULT_FRAME_RATE_BASE;
4209
                video_enc.frame_rate = (int)(strtod(arg, NULL) * video_enc.frame_rate_base);
4210
            }
4211
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4212
            get_arg(arg, sizeof(arg), &p);
4213
            if (stream) {
4214
                video_enc.gop_size = atoi(arg);
4215
            }
4216
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4217
            if (stream) {
4218
                video_enc.gop_size = 1;
4219
            }
4220
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4221
            if (stream) {
4222
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4223
            }
4224
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4225
            if (stream) {
4226
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4227
                video_enc.flags |= CODEC_FLAG_4MV;
4228
            }
4229
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4230
            get_arg(arg, sizeof(arg), &p);
4231
            if (stream) {
4232
                video_enc.max_qdiff = atoi(arg);
4233
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4234
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4235
                            filename, line_num);
4236
                    errors++;
4237
                }
4238
            }
4239
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4240
            get_arg(arg, sizeof(arg), &p);
4241
            if (stream) {
4242
                video_enc.qmax = atoi(arg);
4243
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4244
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4245
                            filename, line_num);
4246
                    errors++;
4247
                }
4248
            }
4249
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4250
            get_arg(arg, sizeof(arg), &p);
4251
            if (stream) {
4252
                video_enc.qmin = atoi(arg);
4253
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4254
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4255
                            filename, line_num);
4256
                    errors++;
4257
                }
4258
            }
4259
        } else if (!strcasecmp(cmd, "LumaElim")) {
4260
            get_arg(arg, sizeof(arg), &p);
4261
            if (stream) {
4262
                video_enc.luma_elim_threshold = atoi(arg);
4263
            }
4264
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4265
            get_arg(arg, sizeof(arg), &p);
4266
            if (stream) {
4267
                video_enc.chroma_elim_threshold = atoi(arg);
4268
            }
4269
        } else if (!strcasecmp(cmd, "LumiMask")) {
4270
            get_arg(arg, sizeof(arg), &p);
4271
            if (stream) {
4272
                video_enc.lumi_masking = atof(arg);
4273
            }
4274
        } else if (!strcasecmp(cmd, "DarkMask")) {
4275
            get_arg(arg, sizeof(arg), &p);
4276
            if (stream) {
4277
                video_enc.dark_masking = atof(arg);
4278
            }
4279
        } else if (!strcasecmp(cmd, "NoVideo")) {
4280
            video_id = CODEC_ID_NONE;
4281
        } else if (!strcasecmp(cmd, "NoAudio")) {
4282
            audio_id = CODEC_ID_NONE;
4283
        } else if (!strcasecmp(cmd, "ACL")) {
4284
            IPAddressACL acl;
4285
            struct hostent *he;
4286

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

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

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

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

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

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

    
4329
                *nacl = acl;
4330
                nacl->next = 0;
4331

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

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

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

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

    
4453
    fclose(f);
4454
    if (errors)
4455
        return -1;
4456
    else
4457
        return 0;
4458
}
4459

    
4460

    
4461
#if 0
4462
static void write_packet(FFCodec *ffenc,
4463
                         uint8_t *buf, int size)
4464
{
4465
    PacketHeader hdr;
4466
    AVCodecContext *enc = &ffenc->enc;
4467
    uint8_t *wptr;
4468
    mk_header(&hdr, enc, size);
4469
    wptr = http_fifo.wptr;
4470
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4471
    fifo_write(&http_fifo, buf, size, &wptr);
4472
    /* atomic modification of wptr */
4473
    http_fifo.wptr = wptr;
4474
    ffenc->data_count += size;
4475
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4476
}
4477
#endif
4478

    
4479
static void show_banner(void)
4480
{
4481
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4482
}
4483

    
4484
static void show_help(void)
4485
{
4486
    show_banner();
4487
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4488
           "Hyper fast multi format Audio/Video streaming server\n"
4489
           "\n"
4490
           "-L            : print the LICENSE\n"
4491
           "-h            : this help\n"
4492
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4493
           );
4494
}
4495

    
4496
static void show_license(void)
4497
{
4498
    show_banner();
4499
    printf(
4500
    "This library is free software; you can redistribute it and/or\n"
4501
    "modify it under the terms of the GNU Lesser General Public\n"
4502
    "License as published by the Free Software Foundation; either\n"
4503
    "version 2 of the License, or (at your option) any later version.\n"
4504
    "\n"
4505
    "This library is distributed in the hope that it will be useful,\n"
4506
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4507
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4508
    "Lesser General Public License for more details.\n"
4509
    "\n"
4510
    "You should have received a copy of the GNU Lesser General Public\n"
4511
    "License along with this library; if not, write to the Free Software\n"
4512
    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4513
    );
4514
}
4515

    
4516
static void handle_child_exit(int sig)
4517
{
4518
    pid_t pid;
4519
    int status;
4520

    
4521
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4522
        FFStream *feed;
4523

    
4524
        for (feed = first_feed; feed; feed = feed->next) {
4525
            if (feed->pid == pid) {
4526
                int uptime = time(0) - feed->pid_start;
4527

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

    
4531
                if (uptime < 30) {
4532
                    /* Turn off any more restarts */
4533
                    feed->child_argv = 0;
4534
                }    
4535
            }
4536
        }
4537
    }
4538

    
4539
    need_to_start_children = 1;
4540
}
4541

    
4542
int main(int argc, char **argv)
4543
{
4544
    const char *config_filename;
4545
    int c;
4546
    struct sigaction sigact;
4547

    
4548
    av_register_all();
4549

    
4550
    config_filename = "/etc/ffserver.conf";
4551

    
4552
    my_program_name = argv[0];
4553
    my_program_dir = getcwd(0, 0);
4554
    ffserver_daemon = 1;
4555
    
4556
    for(;;) {
4557
        c = getopt(argc, argv, "ndLh?f:");
4558
        if (c == -1)
4559
            break;
4560
        switch(c) {
4561
        case 'L':
4562
            show_license();
4563
            exit(1);
4564
        case '?':
4565
        case 'h':
4566
            show_help();
4567
            exit(1);
4568
        case 'n':
4569
            no_launch = 1;
4570
            break;
4571
        case 'd':
4572
            ffserver_debug = 1;
4573
            ffserver_daemon = 0;
4574
            break;
4575
        case 'f':
4576
            config_filename = optarg;
4577
            break;
4578
        default:
4579
            exit(2);
4580
        }
4581
    }
4582

    
4583
    putenv("http_proxy");               /* Kill the http_proxy */
4584

    
4585
    srandom(gettime_ms() + (getpid() << 16));
4586

    
4587
    /* address on which the server will handle HTTP connections */
4588
    my_http_addr.sin_family = AF_INET;
4589
    my_http_addr.sin_port = htons (8080);
4590
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4591

    
4592
    /* address on which the server will handle RTSP connections */
4593
    my_rtsp_addr.sin_family = AF_INET;
4594
    my_rtsp_addr.sin_port = htons (5454);
4595
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4596
    
4597
    nb_max_connections = 5;
4598
    max_bandwidth = 1000;
4599
    first_stream = NULL;
4600
    logfilename[0] = '\0';
4601

    
4602
    memset(&sigact, 0, sizeof(sigact));
4603
    sigact.sa_handler = handle_child_exit;
4604
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4605
    sigaction(SIGCHLD, &sigact, 0);
4606

    
4607
    if (parse_ffconfig(config_filename) < 0) {
4608
        fprintf(stderr, "Incorrect config file - exiting.\n");
4609
        exit(1);
4610
    }
4611

    
4612
    build_file_streams();
4613

    
4614
    build_feed_streams();
4615

    
4616
    compute_bandwidth();
4617

    
4618
    /* put the process in background and detach it from its TTY */
4619
    if (ffserver_daemon) {
4620
        int pid;
4621

    
4622
        pid = fork();
4623
        if (pid < 0) {
4624
            perror("fork");
4625
            exit(1);
4626
        } else if (pid > 0) {
4627
            /* parent : exit */
4628
            exit(0);
4629
        } else {
4630
            /* child */
4631
            setsid();
4632
            chdir("/");
4633
            close(0);
4634
            open("/dev/null", O_RDWR);
4635
            if (strcmp(logfilename, "-") != 0) {
4636
                close(1);
4637
                dup(0);
4638
            }
4639
            close(2);
4640
            dup(0);
4641
        }
4642
    }
4643

    
4644
    /* signal init */
4645
    signal(SIGPIPE, SIG_IGN);
4646

    
4647
    /* open log file if needed */
4648
    if (logfilename[0] != '\0') {
4649
        if (!strcmp(logfilename, "-"))
4650
            logfile = stdout;
4651
        else
4652
            logfile = fopen(logfilename, "w");
4653
    }
4654

    
4655
    if (http_server() < 0) {
4656
        fprintf(stderr, "Could not start server\n");
4657
        exit(1);
4658
    }
4659

    
4660
    return 0;
4661
}