Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ c3f58185

History | View | Annotate | Download (152 KB)

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

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

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

    
50
/* maximum number of simultaneous HTTP connections */
51
#define HTTP_MAX_CONNECTIONS 2000
52

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

    
63
    RTSPSTATE_WAIT_REQUEST,
64
    RTSPSTATE_SEND_REPLY,
65
    RTSPSTATE_SEND_PACKET,
66
};
67

    
68
const char *http_state[] = {
69
    "HTTP_WAIT_REQUEST",
70
    "HTTP_SEND_HEADER",
71

    
72
    "SEND_DATA_HEADER",
73
    "SEND_DATA",
74
    "SEND_DATA_TRAILER",
75
    "RECEIVE_DATA",
76
    "WAIT_FEED",
77
    "READY",
78

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

    
84
#define IOBUFFER_INIT_SIZE 8192
85

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

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

    
93
#define SYNC_TIMEOUT (10 * 1000)
94

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

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

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

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

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

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

    
163
static AVFrame dummy_frame;
164

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

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

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

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

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

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

    
238
struct sockaddr_in my_http_addr;
239
struct sockaddr_in my_rtsp_addr;
240

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

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

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

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

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

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

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

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

    
287
static int nb_max_connections;
288
static int nb_connections;
289

    
290
static int max_bandwidth;
291
static int current_bandwidth;
292

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

    
295
static AVRandomState random_state;
296

    
297
static FILE *logfile = NULL;
298

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

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

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

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

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

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

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

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

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

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

    
362

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

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

    
372
            feed->pid = fork();
373

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

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

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

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

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

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

    
411
                signal(SIGPIPE, SIG_DFL);
412

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

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

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

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

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

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

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

    
450
    return server_fd;
451
}
452

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

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

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

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

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

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

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

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

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

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

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

    
525
    start_children(first_feed);
526

    
527
    first_http_ctx = NULL;
528
    nb_connections = 0;
529

    
530
    start_multicast();
531

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

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

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

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

    
600
        cur_time = av_gettime() / 1000;
601

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

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

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

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

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

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

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

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

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

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

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

    
680
    start_wait_request(c, is_rtsp);
681

    
682
    return;
683

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

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

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

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

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

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

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

    
748
    ctx = &c->fmt_ctx;
749

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
968
                q += 20;
969

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

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

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

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

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

    
995
        p++;
996
    }
997

    
998
    return 0;
999
}
1000

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

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

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

    
1017
        /* Potential stream */
1018

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

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

    
1036
    return best;
1037
}
1038

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

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

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

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

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

    
1074
    return action_required;
1075
}
1076

    
1077

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1235
        p++;
1236
    }
1237

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

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

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

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

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

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

    
1300
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1301
        current_bandwidth += stream->bandwidth;
1302
    }
1303

    
1304
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1305
        c->http_error = 200;
1306
        q = c->buffer;
1307
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1308
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1309
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1310
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
1311
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1312
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1313
            current_bandwidth, max_bandwidth);
1314
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
1315

    
1316
        /* prepare output buffer */
1317
        c->buffer_ptr = c->buffer;
1318
        c->buffer_end = q;
1319
        c->state = HTTPSTATE_SEND_HEADER;
1320
        return 0;
1321
    }
1322

    
1323
    if (redir_type != REDIR_NONE) {
1324
        char *hostinfo = 0;
1325

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

    
1335
            p++;
1336
        }
1337

    
1338
        if (hostinfo) {
1339
            char *eoh;
1340
            char hostbuf[260];
1341

    
1342
            while (isspace(*hostinfo))
1343
                hostinfo++;
1344

    
1345
            eoh = strchr(hostinfo, '\n');
1346
            if (eoh) {
1347
                if (eoh[-1] == '\r')
1348
                    eoh--;
1349

    
1350
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1351
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1352
                    hostbuf[eoh - hostinfo] = 0;
1353

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

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

    
1410
                            len = sizeof(my_addr);
1411
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1412

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

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

    
1439
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1440
        goto send_error;
1441
    }
1442

    
1443
    stream->conns_served++;
1444

    
1445
    /* XXX: add there authenticate and IP match */
1446

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

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

    
1468
                p++;
1469
            }
1470

    
1471
            if (logline) {
1472
                char *eol = strchr(logline, '\n');
1473

    
1474
                logline += 17;
1475

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

    
1484
#ifdef DEBUG_WMP
1485
            http_log("\nGot request:\n%s\n", c->buffer);
1486
#endif
1487

    
1488
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1489
                HTTPContext *wmpc;
1490

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

    
1497
                if (wmpc) {
1498
                    if (modify_current_stream(wmpc, ratebuf)) {
1499
                        wmpc->switch_pending = 1;
1500
                    }
1501
                }
1502
            }
1503

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

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

    
1523
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1524
        goto send_stats;
1525

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

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

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

    
1544
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1545

    
1546
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1547
    }
1548
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1549
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1550

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

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

    
1581
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1582
{
1583
    static const char *suffix = " kMGTP";
1584
    const char *s;
1585

    
1586
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1587
    }
1588

    
1589
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1590
}
1591

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

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

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

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

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

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

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

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

    
1721
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1722
                {
1723
                    FILE *pid_stat;
1724
                    char ps_cmd[64];
1725

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

    
1731
                    pid_stat = popen(ps_cmd, "r");
1732
                    if (pid_stat) {
1733
                        char cpuperc[10];
1734
                        char cpuused[64];
1735

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

    
1746
                url_fprintf(pb, "<p>");
1747
            }
1748
            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");
1749

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

    
1756
                parameters[0] = 0;
1757

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

    
1775
        }
1776
        stream = stream->next;
1777
    }
1778

    
1779
#if 0
1780
    {
1781
        float avg;
1782
        AVCodecContext *enc;
1783
        char buf[1024];
1784

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

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

    
1809
    /* connection status */
1810
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1811

    
1812
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1813
                 nb_connections, nb_max_connections);
1814

    
1815
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1816
                 current_bandwidth, max_bandwidth);
1817

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

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

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

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

    
1864
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1865
    c->buffer_ptr = c->pb_buffer;
1866
    c->buffer_end = c->pb_buffer + len;
1867
}
1868

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

    
1875
    if (!st->codec->codec) {
1876
        codec = avcodec_find_decoder(st->codec->codec_id);
1877
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1878
            st->codec->parse_only = 1;
1879
            if (avcodec_open(st->codec, codec) < 0) {
1880
                st->codec->parse_only = 0;
1881
            }
1882
        }
1883
    }
1884
}
1885

    
1886
static int open_input_stream(HTTPContext *c, const char *info)
1887
{
1888
    char buf[128];
1889
    char input_filename[1024];
1890
    AVFormatContext *s;
1891
    int buf_size, i;
1892
    int64_t stream_pos;
1893

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

    
1920
#if 0
1921
    { time_t when = stream_pos / 1000000;
1922
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1923
    }
1924
#endif
1925

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

    
1934
    /* open each parser */
1935
    for(i=0;i<s->nb_streams;i++)
1936
        open_parser(s, i);
1937

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

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

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

    
1966
/* return the estimated time at which the current packet must be sent
1967
   (in us) */
1968
static int64_t get_packet_send_clock(HTTPContext *c)
1969
{
1970
    int bytes_left, bytes_sent, frame_bytes;
1971

    
1972
    frame_bytes = c->cur_frame_bytes;
1973
    if (frame_bytes <= 0) {
1974
        return c->cur_pts;
1975
    } else {
1976
        bytes_left = c->buffer_end - c->buffer_ptr;
1977
        bytes_sent = frame_bytes - bytes_left;
1978
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1979
    }
1980
}
1981

    
1982

    
1983
static int http_prepare_data(HTTPContext *c)
1984
{
1985
    int i, len, ret;
1986
    AVFormatContext *ctx;
1987

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

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

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

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

    
2035
        av_set_parameters(&c->fmt_ctx, NULL);
2036
        if (av_write_header(&c->fmt_ctx) < 0)
2037
            return -1;
2038

    
2039
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2040
        c->buffer_ptr = c->pb_buffer;
2041
        c->buffer_end = c->pb_buffer + len;
2042

    
2043
        c->state = HTTPSTATE_SEND_DATA;
2044
        c->last_packet_sent = 0;
2045
        break;
2046
    case HTTPSTATE_SEND_DATA:
2047
        /* find a new packet */
2048
        {
2049
            AVPacket pkt;
2050

    
2051
            /* read a packet from the input stream */
2052
            if (c->stream->feed) {
2053
                ffm_set_write_index(c->fmt_in,
2054
                                    c->stream->feed->feed_write_index,
2055
                                    c->stream->feed->feed_size);
2056
            }
2057

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

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

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

    
2190
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2191
                        c->cur_frame_bytes = len;
2192
                        c->buffer_ptr = c->pb_buffer;
2193
                        c->buffer_end = c->pb_buffer + len;
2194

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

    
2220
        c->last_packet_sent = 1;
2221
        break;
2222
    }
2223
    return 0;
2224
}
2225

    
2226
/* in bit/s */
2227
#define SHORT_TERM_BANDWIDTH 8000000
2228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2495
/********************************************************************/
2496
/* RTSP handling */
2497

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

    
2505
    switch(error_number) {
2506
#define DEF(n, c, s) case c: str = s; break;
2507
#include "rtspcodes.h"
2508
#undef DEF
2509
    default:
2510
        str = "Unknown Error";
2511
        break;
2512
    }
2513

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

    
2517
    /* output GMT time */
2518
    ti = time(NULL);
2519
    p = ctime(&ti);
2520
    strcpy(buf2, p);
2521
    p = buf2 + strlen(p) - 1;
2522
    if (*p == '\n')
2523
        *p = '\0';
2524
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2525
}
2526

    
2527
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2528
{
2529
    rtsp_reply_header(c, error_number);
2530
    url_fprintf(c->pb, "\r\n");
2531
}
2532

    
2533
static int rtsp_parse_request(HTTPContext *c)
2534
{
2535
    const char *p, *p1, *p2;
2536
    char cmd[32];
2537
    char url[1024];
2538
    char protocol[32];
2539
    char line[1024];
2540
    ByteIOContext pb1;
2541
    int len;
2542
    RTSPHeader header1, *header = &header1;
2543

    
2544
    c->buffer_ptr[0] = '\0';
2545
    p = c->buffer;
2546

    
2547
    get_word(cmd, sizeof(cmd), &p);
2548
    get_word(url, sizeof(url), &p);
2549
    get_word(protocol, sizeof(protocol), &p);
2550

    
2551
    pstrcpy(c->method, sizeof(c->method), cmd);
2552
    pstrcpy(c->url, sizeof(c->url), url);
2553
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2554

    
2555
    c->pb = &pb1;
2556
    if (url_open_dyn_buf(c->pb) < 0) {
2557
        /* XXX: cannot do more */
2558
        c->pb = NULL; /* safety */
2559
        return -1;
2560
    }
2561

    
2562
    /* check version name */
2563
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2564
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2565
        goto the_end;
2566
    }
2567

    
2568
    /* parse each header line */
2569
    memset(header, 0, sizeof(RTSPHeader));
2570
    /* skip to next line */
2571
    while (*p != '\n' && *p != '\0')
2572
        p++;
2573
    if (*p == '\n')
2574
        p++;
2575
    while (*p != '\0') {
2576
        p1 = strchr(p, '\n');
2577
        if (!p1)
2578
            break;
2579
        p2 = p1;
2580
        if (p2 > p && p2[-1] == '\r')
2581
            p2--;
2582
        /* skip empty line */
2583
        if (p2 == p)
2584
            break;
2585
        len = p2 - p;
2586
        if (len > sizeof(line) - 1)
2587
            len = sizeof(line) - 1;
2588
        memcpy(line, p, len);
2589
        line[len] = '\0';
2590
        rtsp_parse_line(header, line);
2591
        p = p1 + 1;
2592
    }
2593

    
2594
    /* handle sequence number */
2595
    c->seq = header->seq;
2596

    
2597
    if (!strcmp(cmd, "DESCRIBE")) {
2598
        rtsp_cmd_describe(c, url);
2599
    } else if (!strcmp(cmd, "OPTIONS")) {
2600
        rtsp_cmd_options(c, url);
2601
    } else if (!strcmp(cmd, "SETUP")) {
2602
        rtsp_cmd_setup(c, url, header);
2603
    } else if (!strcmp(cmd, "PLAY")) {
2604
        rtsp_cmd_play(c, url, header);
2605
    } else if (!strcmp(cmd, "PAUSE")) {
2606
        rtsp_cmd_pause(c, url, header);
2607
    } else if (!strcmp(cmd, "TEARDOWN")) {
2608
        rtsp_cmd_teardown(c, url, header);
2609
    } else {
2610
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2611
    }
2612
 the_end:
2613
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2614
    c->pb = NULL; /* safety */
2615
    if (len < 0) {
2616
        /* XXX: cannot do more */
2617
        return -1;
2618
    }
2619
    c->buffer_ptr = c->pb_buffer;
2620
    c->buffer_end = c->pb_buffer + len;
2621
    c->state = RTSPSTATE_SEND_REPLY;
2622
    return 0;
2623
}
2624

    
2625
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2626
   AVFormatContext */
2627
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2628
                                   struct in_addr my_ip)
2629
{
2630
    ByteIOContext pb1, *pb = &pb1;
2631
    int i, payload_type, port, private_payload_type, j;
2632
    const char *ipstr, *title, *mediatype;
2633
    AVStream *st;
2634

    
2635
    if (url_open_dyn_buf(pb) < 0)
2636
        return -1;
2637

    
2638
    /* general media info */
2639

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

    
2716
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2717
{
2718
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2719
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2720
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2721
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2722
    url_fprintf(c->pb, "\r\n");
2723
}
2724

    
2725
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2726
{
2727
    FFStream *stream;
2728
    char path1[1024];
2729
    const char *path;
2730
    uint8_t *content;
2731
    int content_length, len;
2732
    struct sockaddr_in my_addr;
2733

    
2734
    /* find which url is asked */
2735
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2736
    path = path1;
2737
    if (*path == '/')
2738
        path++;
2739

    
2740
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2741
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2742
            !strcmp(path, stream->filename)) {
2743
            goto found;
2744
        }
2745
    }
2746
    /* no stream found */
2747
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2748
    return;
2749

    
2750
 found:
2751
    /* prepare the media description in sdp format */
2752

    
2753
    /* get the host IP */
2754
    len = sizeof(my_addr);
2755
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2756
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2757
    if (content_length < 0) {
2758
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2759
        return;
2760
    }
2761
    rtsp_reply_header(c, RTSP_STATUS_OK);
2762
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2763
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2764
    url_fprintf(c->pb, "\r\n");
2765
    put_buffer(c->pb, content, content_length);
2766
}
2767

    
2768
static HTTPContext *find_rtp_session(const char *session_id)
2769
{
2770
    HTTPContext *c;
2771

    
2772
    if (session_id[0] == '\0')
2773
        return NULL;
2774

    
2775
    for(c = first_http_ctx; c != NULL; c = c->next) {
2776
        if (!strcmp(c->session_id, session_id))
2777
            return c;
2778
    }
2779
    return NULL;
2780
}
2781

    
2782
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2783
{
2784
    RTSPTransportField *th;
2785
    int i;
2786

    
2787
    for(i=0;i<h->nb_transports;i++) {
2788
        th = &h->transports[i];
2789
        if (th->protocol == protocol)
2790
            return th;
2791
    }
2792
    return NULL;
2793
}
2794

    
2795
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2796
                           RTSPHeader *h)
2797
{
2798
    FFStream *stream;
2799
    int stream_index, port;
2800
    char buf[1024];
2801
    char path1[1024];
2802
    const char *path;
2803
    HTTPContext *rtp_c;
2804
    RTSPTransportField *th;
2805
    struct sockaddr_in dest_addr;
2806
    RTSPActionServerSetup setup;
2807

    
2808
    /* find which url is asked */
2809
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2810
    path = path1;
2811
    if (*path == '/')
2812
        path++;
2813

    
2814
    /* now check each stream */
2815
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2816
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2817
            /* accept aggregate filenames only if single stream */
2818
            if (!strcmp(path, stream->filename)) {
2819
                if (stream->nb_streams != 1) {
2820
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2821
                    return;
2822
                }
2823
                stream_index = 0;
2824
                goto found;
2825
            }
2826

    
2827
            for(stream_index = 0; stream_index < stream->nb_streams;
2828
                stream_index++) {
2829
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2830
                         stream->filename, stream_index);
2831
                if (!strcmp(path, buf))
2832
                    goto found;
2833
            }
2834
        }
2835
    }
2836
    /* no stream found */
2837
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2838
    return;
2839
 found:
2840

    
2841
    /* generate session id if needed */
2842
    if (h->session_id[0] == '\0') {
2843
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2844
                 av_random(&random_state), av_random(&random_state));
2845
    }
2846

    
2847
    /* find rtp session, and create it if none found */
2848
    rtp_c = find_rtp_session(h->session_id);
2849
    if (!rtp_c) {
2850
        /* always prefer UDP */
2851
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2852
        if (!th) {
2853
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2854
            if (!th) {
2855
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2856
                return;
2857
            }
2858
        }
2859

    
2860
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2861
                                   th->protocol);
2862
        if (!rtp_c) {
2863
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2864
            return;
2865
        }
2866

    
2867
        /* open input stream */
2868
        if (open_input_stream(rtp_c, "") < 0) {
2869
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2870
            return;
2871
        }
2872
    }
2873

    
2874
    /* test if stream is OK (test needed because several SETUP needs
2875
       to be done for a given file) */
2876
    if (rtp_c->stream != stream) {
2877
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2878
        return;
2879
    }
2880

    
2881
    /* test if stream is already set up */
2882
    if (rtp_c->rtp_ctx[stream_index]) {
2883
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2884
        return;
2885
    }
2886

    
2887
    /* check transport */
2888
    th = find_transport(h, rtp_c->rtp_protocol);
2889
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2890
                th->client_port_min <= 0)) {
2891
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2892
        return;
2893
    }
2894

    
2895
    /* setup default options */
2896
    setup.transport_option[0] = '\0';
2897
    dest_addr = rtp_c->from_addr;
2898
    dest_addr.sin_port = htons(th->client_port_min);
2899

    
2900
    /* add transport option if needed */
2901
    if (ff_rtsp_callback) {
2902
        setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2903
        if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id,
2904
                             (char *)&setup, sizeof(setup),
2905
                             stream->rtsp_option) < 0) {
2906
            rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2907
            return;
2908
        }
2909
        dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2910
    }
2911

    
2912
    /* setup stream */
2913
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2914
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2915
        return;
2916
    }
2917

    
2918
    /* now everything is OK, so we can send the connection parameters */
2919
    rtsp_reply_header(c, RTSP_STATUS_OK);
2920
    /* session ID */
2921
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2922

    
2923
    switch(rtp_c->rtp_protocol) {
2924
    case RTSP_PROTOCOL_RTP_UDP:
2925
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2926
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2927
                    "client_port=%d-%d;server_port=%d-%d",
2928
                    th->client_port_min, th->client_port_min + 1,
2929
                    port, port + 1);
2930
        break;
2931
    case RTSP_PROTOCOL_RTP_TCP:
2932
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2933
                    stream_index * 2, stream_index * 2 + 1);
2934
        break;
2935
    default:
2936
        break;
2937
    }
2938
    if (setup.transport_option[0] != '\0') {
2939
        url_fprintf(c->pb, ";%s", setup.transport_option);
2940
    }
2941
    url_fprintf(c->pb, "\r\n");
2942

    
2943

    
2944
    url_fprintf(c->pb, "\r\n");
2945
}
2946

    
2947

    
2948
/* find an rtp connection by using the session ID. Check consistency
2949
   with filename */
2950
static HTTPContext *find_rtp_session_with_url(const char *url,
2951
                                              const char *session_id)
2952
{
2953
    HTTPContext *rtp_c;
2954
    char path1[1024];
2955
    const char *path;
2956
    char buf[1024];
2957
    int s;
2958

    
2959
    rtp_c = find_rtp_session(session_id);
2960
    if (!rtp_c)
2961
        return NULL;
2962

    
2963
    /* find which url is asked */
2964
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2965
    path = path1;
2966
    if (*path == '/')
2967
        path++;
2968
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2969
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2970
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2971
        rtp_c->stream->filename, s);
2972
      if(!strncmp(path, buf, sizeof(buf))) {
2973
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2974
        return rtp_c;
2975
      }
2976
    }
2977
    return NULL;
2978
}
2979

    
2980
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2981
{
2982
    HTTPContext *rtp_c;
2983

    
2984
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2985
    if (!rtp_c) {
2986
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2987
        return;
2988
    }
2989

    
2990
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2991
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2992
        rtp_c->state != HTTPSTATE_READY) {
2993
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2994
        return;
2995
    }
2996

    
2997
#if 0
2998
    /* XXX: seek in stream */
2999
    if (h->range_start != AV_NOPTS_VALUE) {
3000
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3001
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3002
    }
3003
#endif
3004

    
3005
    rtp_c->state = HTTPSTATE_SEND_DATA;
3006

    
3007
    /* now everything is OK, so we can send the connection parameters */
3008
    rtsp_reply_header(c, RTSP_STATUS_OK);
3009
    /* session ID */
3010
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3011
    url_fprintf(c->pb, "\r\n");
3012
}
3013

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

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

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

    
3030
    rtp_c->state = HTTPSTATE_READY;
3031
    rtp_c->first_pts = AV_NOPTS_VALUE;
3032
    /* now everything is OK, so we can send the connection parameters */
3033
    rtsp_reply_header(c, RTSP_STATUS_OK);
3034
    /* session ID */
3035
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3036
    url_fprintf(c->pb, "\r\n");
3037
}
3038

    
3039
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3040
{
3041
    HTTPContext *rtp_c;
3042

    
3043
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3044
    if (!rtp_c) {
3045
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3046
        return;
3047
    }
3048

    
3049
    /* abort the session */
3050
    close_connection(rtp_c);
3051

    
3052
    if (ff_rtsp_callback) {
3053
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3054
                         NULL, 0,
3055
                         rtp_c->stream->rtsp_option);
3056
    }
3057

    
3058
    /* now everything is OK, so we can send the connection parameters */
3059
    rtsp_reply_header(c, RTSP_STATUS_OK);
3060
    /* session ID */
3061
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3062
    url_fprintf(c->pb, "\r\n");
3063
}
3064

    
3065

    
3066
/********************************************************************/
3067
/* RTP handling */
3068

    
3069
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3070
                                       FFStream *stream, const char *session_id,
3071
                                       enum RTSPProtocol rtp_protocol)
3072
{
3073
    HTTPContext *c = NULL;
3074
    const char *proto_str;
3075

    
3076
    /* XXX: should output a warning page when coming
3077
       close to the connection limit */
3078
    if (nb_connections >= nb_max_connections)
3079
        goto fail;
3080

    
3081
    /* add a new connection */
3082
    c = av_mallocz(sizeof(HTTPContext));
3083
    if (!c)
3084
        goto fail;
3085

    
3086
    c->fd = -1;
3087
    c->poll_entry = NULL;
3088
    c->from_addr = *from_addr;
3089
    c->buffer_size = IOBUFFER_INIT_SIZE;
3090
    c->buffer = av_malloc(c->buffer_size);
3091
    if (!c->buffer)
3092
        goto fail;
3093
    nb_connections++;
3094
    c->stream = stream;
3095
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3096
    c->state = HTTPSTATE_READY;
3097
    c->is_packetized = 1;
3098
    c->rtp_protocol = rtp_protocol;
3099

    
3100
    /* protocol is shown in statistics */
3101
    switch(c->rtp_protocol) {
3102
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3103
        proto_str = "MCAST";
3104
        break;
3105
    case RTSP_PROTOCOL_RTP_UDP:
3106
        proto_str = "UDP";
3107
        break;
3108
    case RTSP_PROTOCOL_RTP_TCP:
3109
        proto_str = "TCP";
3110
        break;
3111
    default:
3112
        proto_str = "???";
3113
        break;
3114
    }
3115
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3116
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3117

    
3118
    current_bandwidth += stream->bandwidth;
3119

    
3120
    c->next = first_http_ctx;
3121
    first_http_ctx = c;
3122
    return c;
3123

    
3124
 fail:
3125
    if (c) {
3126
        av_free(c->buffer);
3127
        av_free(c);
3128
    }
3129
    return NULL;
3130
}
3131

    
3132
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3133
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3134
   used. */
3135
static int rtp_new_av_stream(HTTPContext *c,
3136
                             int stream_index, struct sockaddr_in *dest_addr,
3137
                             HTTPContext *rtsp_c)
3138
{
3139
    AVFormatContext *ctx;
3140
    AVStream *st;
3141
    char *ipaddr;
3142
    URLContext *h;
3143
    uint8_t *dummy_buf;
3144
    char buf2[32];
3145
    int max_packet_size;
3146

    
3147
    /* now we can open the relevant output stream */
3148
    ctx = av_alloc_format_context();
3149
    if (!ctx)
3150
        return -1;
3151
    ctx->oformat = &rtp_muxer;
3152

    
3153
    st = av_mallocz(sizeof(AVStream));
3154
    if (!st)
3155
        goto fail;
3156
    st->codec= avcodec_alloc_context();
3157
    ctx->nb_streams = 1;
3158
    ctx->streams[0] = st;
3159

    
3160
    if (!c->stream->feed ||
3161
        c->stream->feed == c->stream) {
3162
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3163
    } else {
3164
        memcpy(st,
3165
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3166
               sizeof(AVStream));
3167
    }
3168

    
3169
    /* build destination RTP address */
3170
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3171

    
3172
    switch(c->rtp_protocol) {
3173
    case RTSP_PROTOCOL_RTP_UDP:
3174
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3175
        /* RTP/UDP case */
3176

    
3177
        /* XXX: also pass as parameter to function ? */
3178
        if (c->stream->is_multicast) {
3179
            int ttl;
3180
            ttl = c->stream->multicast_ttl;
3181
            if (!ttl)
3182
                ttl = 16;
3183
            snprintf(ctx->filename, sizeof(ctx->filename),
3184
                     "rtp://%s:%d?multicast=1&ttl=%d",
3185
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3186
        } else {
3187
            snprintf(ctx->filename, sizeof(ctx->filename),
3188
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3189
        }
3190

    
3191
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3192
            goto fail;
3193
        c->rtp_handles[stream_index] = h;
3194
        max_packet_size = url_get_max_packet_size(h);
3195
        break;
3196
    case RTSP_PROTOCOL_RTP_TCP:
3197
        /* RTP/TCP case */
3198
        c->rtsp_c = rtsp_c;
3199
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3200
        break;
3201
    default:
3202
        goto fail;
3203
    }
3204

    
3205
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3206
             ipaddr, ntohs(dest_addr->sin_port),
3207
             ctime1(buf2),
3208
             c->stream->filename, stream_index, c->protocol);
3209

    
3210
    /* normally, no packets should be output here, but the packet size may be checked */
3211
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3212
        /* XXX: close stream */
3213
        goto fail;
3214
    }
3215
    av_set_parameters(ctx, NULL);
3216
    if (av_write_header(ctx) < 0) {
3217
    fail:
3218
        if (h)
3219
            url_close(h);
3220
        av_free(ctx);
3221
        return -1;
3222
    }
3223
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3224
    av_free(dummy_buf);
3225

    
3226
    c->rtp_ctx[stream_index] = ctx;
3227
    return 0;
3228
}
3229

    
3230
/********************************************************************/
3231
/* ffserver initialization */
3232

    
3233
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3234
{
3235
    AVStream *fst;
3236

    
3237
    fst = av_mallocz(sizeof(AVStream));
3238
    if (!fst)
3239
        return NULL;
3240
    fst->codec= avcodec_alloc_context();
3241
    fst->priv_data = av_mallocz(sizeof(FeedData));
3242
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3243
    fst->codec->coded_frame = &dummy_frame;
3244
    fst->index = stream->nb_streams;
3245
    av_set_pts_info(fst, 33, 1, 90000);
3246
    stream->streams[stream->nb_streams++] = fst;
3247
    return fst;
3248
}
3249

    
3250
/* return the stream number in the feed */
3251
static int add_av_stream(FFStream *feed, AVStream *st)
3252
{
3253
    AVStream *fst;
3254
    AVCodecContext *av, *av1;
3255
    int i;
3256

    
3257
    av = st->codec;
3258
    for(i=0;i<feed->nb_streams;i++) {
3259
        st = feed->streams[i];
3260
        av1 = st->codec;
3261
        if (av1->codec_id == av->codec_id &&
3262
            av1->codec_type == av->codec_type &&
3263
            av1->bit_rate == av->bit_rate) {
3264

    
3265
            switch(av->codec_type) {
3266
            case CODEC_TYPE_AUDIO:
3267
                if (av1->channels == av->channels &&
3268
                    av1->sample_rate == av->sample_rate)
3269
                    goto found;
3270
                break;
3271
            case CODEC_TYPE_VIDEO:
3272
                if (av1->width == av->width &&
3273
                    av1->height == av->height &&
3274
                    av1->time_base.den == av->time_base.den &&
3275
                    av1->time_base.num == av->time_base.num &&
3276
                    av1->gop_size == av->gop_size)
3277
                    goto found;
3278
                break;
3279
            default:
3280
                av_abort();
3281
            }
3282
        }
3283
    }
3284

    
3285
    fst = add_av_stream1(feed, av);
3286
    if (!fst)
3287
        return -1;
3288
    return feed->nb_streams - 1;
3289
 found:
3290
    return i;
3291
}
3292

    
3293
static void remove_stream(FFStream *stream)
3294
{
3295
    FFStream **ps;
3296
    ps = &first_stream;
3297
    while (*ps != NULL) {
3298
        if (*ps == stream) {
3299
            *ps = (*ps)->next;
3300
        } else {
3301
            ps = &(*ps)->next;
3302
        }
3303
    }
3304
}
3305

    
3306
/* specific mpeg4 handling : we extract the raw parameters */
3307
static void extract_mpeg4_header(AVFormatContext *infile)
3308
{
3309
    int mpeg4_count, i, size;
3310
    AVPacket pkt;
3311
    AVStream *st;
3312
    const uint8_t *p;
3313

    
3314
    mpeg4_count = 0;
3315
    for(i=0;i<infile->nb_streams;i++) {
3316
        st = infile->streams[i];
3317
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3318
            st->codec->extradata_size == 0) {
3319
            mpeg4_count++;
3320
        }
3321
    }
3322
    if (!mpeg4_count)
3323
        return;
3324

    
3325
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3326
    while (mpeg4_count > 0) {
3327
        if (av_read_packet(infile, &pkt) < 0)
3328
            break;
3329
        st = infile->streams[pkt.stream_index];
3330
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3331
            st->codec->extradata_size == 0) {
3332
            av_freep(&st->codec->extradata);
3333
            /* fill extradata with the header */
3334
            /* XXX: we make hard suppositions here ! */
3335
            p = pkt.data;
3336
            while (p < pkt.data + pkt.size - 4) {
3337
                /* stop when vop header is found */
3338
                if (p[0] == 0x00 && p[1] == 0x00 &&
3339
                    p[2] == 0x01 && p[3] == 0xb6) {
3340
                    size = p - pkt.data;
3341
                    //                    av_hex_dump(pkt.data, size);
3342
                    st->codec->extradata = av_malloc(size);
3343
                    st->codec->extradata_size = size;
3344
                    memcpy(st->codec->extradata, pkt.data, size);
3345
                    break;
3346
                }
3347
                p++;
3348
            }
3349
            mpeg4_count--;
3350
        }
3351
        av_free_packet(&pkt);
3352
    }
3353
}
3354

    
3355
/* compute the needed AVStream for each file */
3356
static void build_file_streams(void)
3357
{
3358
    FFStream *stream, *stream_next;
3359
    AVFormatContext *infile;
3360
    int i;
3361

    
3362
    /* gather all streams */
3363
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3364
        stream_next = stream->next;
3365
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3366
            !stream->feed) {
3367
            /* the stream comes from a file */
3368
            /* try to open the file */
3369
            /* open stream */
3370
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3371
            if (stream->fmt == &rtp_muxer) {
3372
                /* specific case : if transport stream output to RTP,
3373
                   we use a raw transport stream reader */
3374
                stream->ap_in->mpeg2ts_raw = 1;
3375
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3376
            }
3377

    
3378
            if (av_open_input_file(&infile, stream->feed_filename,
3379
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3380
                http_log("%s not found", stream->feed_filename);
3381
                /* remove stream (no need to spend more time on it) */
3382
            fail:
3383
                remove_stream(stream);
3384
            } else {
3385
                /* find all the AVStreams inside and reference them in
3386
                   'stream' */
3387
                if (av_find_stream_info(infile) < 0) {
3388
                    http_log("Could not find codec parameters from '%s'",
3389
                             stream->feed_filename);
3390
                    av_close_input_file(infile);
3391
                    goto fail;
3392
                }
3393
                extract_mpeg4_header(infile);
3394

    
3395
                for(i=0;i<infile->nb_streams;i++) {
3396
                    add_av_stream1(stream, infile->streams[i]->codec);
3397
                }
3398
                av_close_input_file(infile);
3399
            }
3400
        }
3401
    }
3402
}
3403

    
3404
/* compute the needed AVStream for each feed */
3405
static void build_feed_streams(void)
3406
{
3407
    FFStream *stream, *feed;
3408
    int i;
3409

    
3410
    /* gather all streams */
3411
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3412
        feed = stream->feed;
3413
        if (feed) {
3414
            if (!stream->is_feed) {
3415
                /* we handle a stream coming from a feed */
3416
                for(i=0;i<stream->nb_streams;i++) {
3417
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3418
                }
3419
            }
3420
        }
3421
    }
3422

    
3423
    /* gather all streams */
3424
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3425
        feed = stream->feed;
3426
        if (feed) {
3427
            if (stream->is_feed) {
3428
                for(i=0;i<stream->nb_streams;i++) {
3429
                    stream->feed_streams[i] = i;
3430
                }
3431
            }
3432
        }
3433
    }
3434

    
3435
    /* create feed files if needed */
3436
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3437
        int fd;
3438

    
3439
        if (url_exist(feed->feed_filename)) {
3440
            /* See if it matches */
3441
            AVFormatContext *s;
3442
            int matches = 0;
3443

    
3444
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3445
                /* Now see if it matches */
3446
                if (s->nb_streams == feed->nb_streams) {
3447
                    matches = 1;
3448
                    for(i=0;i<s->nb_streams;i++) {
3449
                        AVStream *sf, *ss;
3450
                        sf = feed->streams[i];
3451
                        ss = s->streams[i];
3452

    
3453
                        if (sf->index != ss->index ||
3454
                            sf->id != ss->id) {
3455
                            printf("Index & Id do not match for stream %d (%s)\n",
3456
                                   i, feed->feed_filename);
3457
                            matches = 0;
3458
                        } else {
3459
                            AVCodecContext *ccf, *ccs;
3460

    
3461
                            ccf = sf->codec;
3462
                            ccs = ss->codec;
3463
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3464

    
3465
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3466
                                printf("Codecs do not match for stream %d\n", i);
3467
                                matches = 0;
3468
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3469
                                printf("Codec bitrates do not match for stream %d\n", i);
3470
                                matches = 0;
3471
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3472
                                if (CHECK_CODEC(time_base.den) ||
3473
                                    CHECK_CODEC(time_base.num) ||
3474
                                    CHECK_CODEC(width) ||
3475
                                    CHECK_CODEC(height)) {
3476
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3477
                                    matches = 0;
3478
                                }
3479
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3480
                                if (CHECK_CODEC(sample_rate) ||
3481
                                    CHECK_CODEC(channels) ||
3482
                                    CHECK_CODEC(frame_size)) {
3483
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3484
                                    matches = 0;
3485
                                }
3486
                            } else {
3487
                                printf("Unknown codec type\n");
3488
                                matches = 0;
3489
                            }
3490
                        }
3491
                        if (!matches) {
3492
                            break;
3493
                        }
3494
                    }
3495
                } else {
3496
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3497
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3498
                }
3499

    
3500
                av_close_input_file(s);
3501
            } else {
3502
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3503
                        feed->feed_filename);
3504
            }
3505
            if (!matches) {
3506
                if (feed->readonly) {
3507
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3508
                        feed->feed_filename);
3509
                    exit(1);
3510
                }
3511
                unlink(feed->feed_filename);
3512
            }
3513
        }
3514
        if (!url_exist(feed->feed_filename)) {
3515
            AVFormatContext s1, *s = &s1;
3516

    
3517
            if (feed->readonly) {
3518
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3519
                    feed->feed_filename);
3520
                exit(1);
3521
            }
3522

    
3523
            /* only write the header of the ffm file */
3524
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3525
                fprintf(stderr, "Could not open output feed file '%s'\n",
3526
                        feed->feed_filename);
3527
                exit(1);
3528
            }
3529
            s->oformat = feed->fmt;
3530
            s->nb_streams = feed->nb_streams;
3531
            for(i=0;i<s->nb_streams;i++) {
3532
                AVStream *st;
3533
                st = feed->streams[i];
3534
                s->streams[i] = st;
3535
            }
3536
            av_set_parameters(s, NULL);
3537
            if (av_write_header(s) < 0) {
3538
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3539
                exit(1);
3540
            }
3541
            /* XXX: need better api */
3542
            av_freep(&s->priv_data);
3543
            url_fclose(&s->pb);
3544
        }
3545
        /* get feed size and write index */
3546
        fd = open(feed->feed_filename, O_RDONLY);
3547
        if (fd < 0) {
3548
            fprintf(stderr, "Could not open output feed file '%s'\n",
3549
                    feed->feed_filename);
3550
            exit(1);
3551
        }
3552

    
3553
        feed->feed_write_index = ffm_read_write_index(fd);
3554
        feed->feed_size = lseek(fd, 0, SEEK_END);
3555
        /* ensure that we do not wrap before the end of file */
3556
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3557
            feed->feed_max_size = feed->feed_size;
3558

    
3559
        close(fd);
3560
    }
3561
}
3562

    
3563
/* compute the bandwidth used by each stream */
3564
static void compute_bandwidth(void)
3565
{
3566
    int bandwidth, i;
3567
    FFStream *stream;
3568

    
3569
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3570
        bandwidth = 0;
3571
        for(i=0;i<stream->nb_streams;i++) {
3572
            AVStream *st = stream->streams[i];
3573
            switch(st->codec->codec_type) {
3574
            case CODEC_TYPE_AUDIO:
3575
            case CODEC_TYPE_VIDEO:
3576
                bandwidth += st->codec->bit_rate;
3577
                break;
3578
            default:
3579
                break;
3580
            }
3581
        }
3582
        stream->bandwidth = (bandwidth + 999) / 1000;
3583
    }
3584
}
3585

    
3586
static void get_arg(char *buf, int buf_size, const char **pp)
3587
{
3588
    const char *p;
3589
    char *q;
3590
    int quote;
3591

    
3592
    p = *pp;
3593
    while (isspace(*p)) p++;
3594
    q = buf;
3595
    quote = 0;
3596
    if (*p == '\"' || *p == '\'')
3597
        quote = *p++;
3598
    for(;;) {
3599
        if (quote) {
3600
            if (*p == quote)
3601
                break;
3602
        } else {
3603
            if (isspace(*p))
3604
                break;
3605
        }
3606
        if (*p == '\0')
3607
            break;
3608
        if ((q - buf) < buf_size - 1)
3609
            *q++ = *p;
3610
        p++;
3611
    }
3612
    *q = '\0';
3613
    if (quote && *p == quote)
3614
        p++;
3615
    *pp = p;
3616
}
3617

    
3618
/* add a codec and set the default parameters */
3619
static void add_codec(FFStream *stream, AVCodecContext *av)
3620
{
3621
    AVStream *st;
3622

    
3623
    /* compute default parameters */
3624
    switch(av->codec_type) {
3625
    case CODEC_TYPE_AUDIO:
3626
        if (av->bit_rate == 0)
3627
            av->bit_rate = 64000;
3628
        if (av->sample_rate == 0)
3629
            av->sample_rate = 22050;
3630
        if (av->channels == 0)
3631
            av->channels = 1;
3632
        break;
3633
    case CODEC_TYPE_VIDEO:
3634
        if (av->bit_rate == 0)
3635
            av->bit_rate = 64000;
3636
        if (av->time_base.num == 0){
3637
            av->time_base.den = 5;
3638
            av->time_base.num = 1;
3639
        }
3640
        if (av->width == 0 || av->height == 0) {
3641
            av->width = 160;
3642
            av->height = 128;
3643
        }
3644
        /* Bitrate tolerance is less for streaming */
3645
        if (av->bit_rate_tolerance == 0)
3646
            av->bit_rate_tolerance = av->bit_rate / 4;
3647
        if (av->qmin == 0)
3648
            av->qmin = 3;
3649
        if (av->qmax == 0)
3650
            av->qmax = 31;
3651
        if (av->max_qdiff == 0)
3652
            av->max_qdiff = 3;
3653
        av->qcompress = 0.5;
3654
        av->qblur = 0.5;
3655

    
3656
        if (!av->nsse_weight)
3657
            av->nsse_weight = 8;
3658

    
3659
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3660
        av->me_method = ME_EPZS;
3661
        av->rc_buffer_aggressivity = 1.0;
3662

    
3663
        if (!av->rc_eq)
3664
            av->rc_eq = "tex^qComp";
3665
        if (!av->i_quant_factor)
3666
            av->i_quant_factor = -0.8;
3667
        if (!av->b_quant_factor)
3668
            av->b_quant_factor = 1.25;
3669
        if (!av->b_quant_offset)
3670
            av->b_quant_offset = 1.25;
3671
        if (!av->rc_max_rate)
3672
            av->rc_max_rate = av->bit_rate * 2;
3673

    
3674
        if (av->rc_max_rate && !av->rc_buffer_size) {
3675
            av->rc_buffer_size = av->rc_max_rate;
3676
        }
3677

    
3678

    
3679
        break;
3680
    default:
3681
        av_abort();
3682
    }
3683

    
3684
    st = av_mallocz(sizeof(AVStream));
3685
    if (!st)
3686
        return;
3687
    st->codec = avcodec_alloc_context();
3688
    stream->streams[stream->nb_streams++] = st;
3689
    memcpy(st->codec, av, sizeof(AVCodecContext));
3690
}
3691

    
3692
static int opt_audio_codec(const char *arg)
3693
{
3694
    AVCodec *p;
3695

    
3696
    p = first_avcodec;
3697
    while (p) {
3698
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3699
            break;
3700
        p = p->next;
3701
    }
3702
    if (p == NULL) {
3703
        return CODEC_ID_NONE;
3704
    }
3705

    
3706
    return p->id;
3707
}
3708

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

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

    
3723
    return p->id;
3724
}
3725

    
3726
/* simplistic plugin support */
3727

    
3728
#ifdef HAVE_DLOPEN
3729
static void load_module(const char *filename)
3730
{
3731
    void *dll;
3732
    void (*init_func)(void);
3733
    dll = dlopen(filename, RTLD_NOW);
3734
    if (!dll) {
3735
        fprintf(stderr, "Could not load module '%s' - %s\n",
3736
                filename, dlerror());
3737
        return;
3738
    }
3739

    
3740
    init_func = dlsym(dll, "ffserver_module_init");
3741
    if (!init_func) {
3742
        fprintf(stderr,
3743
                "%s: init function 'ffserver_module_init()' not found\n",
3744
                filename);
3745
        dlclose(dll);
3746
    }
3747

    
3748
    init_func();
3749
}
3750
#endif
3751

    
3752
static int parse_ffconfig(const char *filename)
3753
{
3754
    FILE *f;
3755
    char line[1024];
3756
    char cmd[64];
3757
    char arg[1024];
3758
    const char *p;
3759
    int val, errors, line_num;
3760
    FFStream **last_stream, *stream, *redirect;
3761
    FFStream **last_feed, *feed;
3762
    AVCodecContext audio_enc, video_enc;
3763
    int audio_id, video_id;
3764

    
3765
    f = fopen(filename, "r");
3766
    if (!f) {
3767
        perror(filename);
3768
        return -1;
3769
    }
3770

    
3771
    errors = 0;
3772
    line_num = 0;
3773
    first_stream = NULL;
3774
    last_stream = &first_stream;
3775
    first_feed = NULL;
3776
    last_feed = &first_feed;
3777
    stream = NULL;
3778
    feed = NULL;
3779
    redirect = NULL;
3780
    audio_id = CODEC_ID_NONE;
3781
    video_id = CODEC_ID_NONE;
3782
    for(;;) {
3783
        if (fgets(line, sizeof(line), f) == NULL)
3784
            break;
3785
        line_num++;
3786
        p = line;
3787
        while (isspace(*p))
3788
            p++;
3789
        if (*p == '\0' || *p == '#')
3790
            continue;
3791

    
3792
        get_arg(cmd, sizeof(cmd), &p);
3793

    
3794
        if (!strcasecmp(cmd, "Port")) {
3795
            get_arg(arg, sizeof(arg), &p);
3796
            my_http_addr.sin_port = htons (atoi(arg));
3797
        } else if (!strcasecmp(cmd, "BindAddress")) {
3798
            get_arg(arg, sizeof(arg), &p);
3799
            if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3800
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3801
                        filename, line_num, arg);
3802
                errors++;
3803
            }
3804
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3805
            ffserver_daemon = 0;
3806
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3807
            get_arg(arg, sizeof(arg), &p);
3808
            my_rtsp_addr.sin_port = htons (atoi(arg));
3809
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3810
            get_arg(arg, sizeof(arg), &p);
3811
            if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3812
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
3813
                        filename, line_num, arg);
3814
                errors++;
3815
            }
3816
        } else if (!strcasecmp(cmd, "MaxClients")) {
3817
            get_arg(arg, sizeof(arg), &p);
3818
            val = atoi(arg);
3819
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3820
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3821
                        filename, line_num, arg);
3822
                errors++;
3823
            } else {
3824
                nb_max_connections = val;
3825
            }
3826
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3827
            get_arg(arg, sizeof(arg), &p);
3828
            val = atoi(arg);
3829
            if (val < 10 || val > 100000) {
3830
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3831
                        filename, line_num, arg);
3832
                errors++;
3833
            } else {
3834
                max_bandwidth = val;
3835
            }
3836
        } else if (!strcasecmp(cmd, "CustomLog")) {
3837
            get_arg(logfilename, sizeof(logfilename), &p);
3838
        } else if (!strcasecmp(cmd, "<Feed")) {
3839
            /*********************************************/
3840
            /* Feed related options */
3841
            char *q;
3842
            if (stream || feed) {
3843
                fprintf(stderr, "%s:%d: Already in a tag\n",
3844
                        filename, line_num);
3845
            } else {
3846
                feed = av_mallocz(sizeof(FFStream));
3847
                /* add in stream list */
3848
                *last_stream = feed;
3849
                last_stream = &feed->next;
3850
                /* add in feed list */
3851
                *last_feed = feed;
3852
                last_feed = &feed->next_feed;
3853

    
3854
                get_arg(feed->filename, sizeof(feed->filename), &p);
3855
                q = strrchr(feed->filename, '>');
3856
                if (*q)
3857
                    *q = '\0';
3858
                feed->fmt = guess_format("ffm", NULL, NULL);
3859
                /* defaut feed file */
3860
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3861
                         "/tmp/%s.ffm", feed->filename);
3862
                feed->feed_max_size = 5 * 1024 * 1024;
3863
                feed->is_feed = 1;
3864
                feed->feed = feed; /* self feeding :-) */
3865
            }
3866
        } else if (!strcasecmp(cmd, "Launch")) {
3867
            if (feed) {
3868
                int i;
3869

    
3870
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3871

    
3872
                for (i = 0; i < 62; i++) {
3873
                    char argbuf[256];
3874

    
3875
                    get_arg(argbuf, sizeof(argbuf), &p);
3876
                    if (!argbuf[0])
3877
                        break;
3878

    
3879
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3880
                    strcpy(feed->child_argv[i], argbuf);
3881
                }
3882

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

    
3885
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3886
                    "http://%s:%d/%s",
3887
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3888
                    inet_ntoa(my_http_addr.sin_addr),
3889
                    ntohs(my_http_addr.sin_port), feed->filename);
3890

    
3891
                if (ffserver_debug)
3892
                {
3893
                    int j;
3894
                    fprintf(stdout, "Launch commandline: ");
3895
                    for (j = 0; j <= i; j++)
3896
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3897
                    fprintf(stdout, "\n");
3898
                }
3899
            }
3900
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3901
            if (feed) {
3902
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3903
                feed->readonly = 1;
3904
            } else if (stream) {
3905
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3906
            }
3907
        } else if (!strcasecmp(cmd, "File")) {
3908
            if (feed) {
3909
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3910
            } else if (stream) {
3911
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3912
            }
3913
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3914
            if (feed) {
3915
                const char *p1;
3916
                double fsize;
3917

    
3918
                get_arg(arg, sizeof(arg), &p);
3919
                p1 = arg;
3920
                fsize = strtod(p1, (char **)&p1);
3921
                switch(toupper(*p1)) {
3922
                case 'K':
3923
                    fsize *= 1024;
3924
                    break;
3925
                case 'M':
3926
                    fsize *= 1024 * 1024;
3927
                    break;
3928
                case 'G':
3929
                    fsize *= 1024 * 1024 * 1024;
3930
                    break;
3931
                }
3932
                feed->feed_max_size = (int64_t)fsize;
3933
            }
3934
        } else if (!strcasecmp(cmd, "</Feed>")) {
3935
            if (!feed) {
3936
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3937
                        filename, line_num);
3938
                errors++;
3939
#if 0
3940
            } else {
3941
                /* Make sure that we start out clean */
3942
                if (unlink(feed->feed_filename) < 0
3943
                    && errno != ENOENT) {
3944
                    fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3945
                        filename, line_num, feed->feed_filename, strerror(errno));
3946
                    errors++;
3947
                }
3948
#endif
3949
            }
3950
            feed = NULL;
3951
        } else if (!strcasecmp(cmd, "<Stream")) {
3952
            /*********************************************/
3953
            /* Stream related options */
3954
            char *q;
3955
            if (stream || feed) {
3956
                fprintf(stderr, "%s:%d: Already in a tag\n",
3957
                        filename, line_num);
3958
            } else {
3959
                stream = av_mallocz(sizeof(FFStream));
3960
                *last_stream = stream;
3961
                last_stream = &stream->next;
3962

    
3963
                get_arg(stream->filename, sizeof(stream->filename), &p);
3964
                q = strrchr(stream->filename, '>');
3965
                if (*q)
3966
                    *q = '\0';
3967
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3968
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3969
                memset(&video_enc, 0, sizeof(AVCodecContext));
3970
                audio_id = CODEC_ID_NONE;
3971
                video_id = CODEC_ID_NONE;
3972
                if (stream->fmt) {
3973
                    audio_id = stream->fmt->audio_codec;
3974
                    video_id = stream->fmt->video_codec;
3975
                }
3976
            }
3977
        } else if (!strcasecmp(cmd, "Feed")) {
3978
            get_arg(arg, sizeof(arg), &p);
3979
            if (stream) {
3980
                FFStream *sfeed;
3981

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

    
4100
                get_arg(arg, sizeof(arg), &p);
4101

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

    
4252
            get_arg(arg, sizeof(arg), &p);
4253
            if (strcasecmp(arg, "allow") == 0) {
4254
                acl.action = IP_ALLOW;
4255
            } else if (strcasecmp(arg, "deny") == 0) {
4256
                acl.action = IP_DENY;
4257
            } else {
4258
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4259
                        filename, line_num, arg);
4260
                errors++;
4261
            }
4262

    
4263
            get_arg(arg, sizeof(arg), &p);
4264

    
4265
            he = gethostbyname(arg);
4266
            if (!he) {
4267
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4268
                        filename, line_num, arg);
4269
                errors++;
4270
            } else {
4271
                /* Only take the first */
4272
                acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4273
                acl.last = acl.first;
4274
            }
4275

    
4276
            get_arg(arg, sizeof(arg), &p);
4277

    
4278
            if (arg[0]) {
4279
                he = gethostbyname(arg);
4280
                if (!he) {
4281
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4282
                            filename, line_num, arg);
4283
                    errors++;
4284
                } else {
4285
                    /* Only take the first */
4286
                    acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4287
                }
4288
            }
4289

    
4290
            if (!errors) {
4291
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4292
                IPAddressACL **naclp = 0;
4293

    
4294
                *nacl = acl;
4295
                nacl->next = 0;
4296

    
4297
                if (stream) {
4298
                    naclp = &stream->acl;
4299
                } else if (feed) {
4300
                    naclp = &feed->acl;
4301
                } else {
4302
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4303
                            filename, line_num);
4304
                    errors++;
4305
                }
4306

    
4307
                if (naclp) {
4308
                    while (*naclp)
4309
                        naclp = &(*naclp)->next;
4310

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

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

    
4418
    fclose(f);
4419
    if (errors)
4420
        return -1;
4421
    else
4422
        return 0;
4423
}
4424

    
4425

    
4426
#if 0
4427
static void write_packet(FFCodec *ffenc,
4428
                         uint8_t *buf, int size)
4429
{
4430
    PacketHeader hdr;
4431
    AVCodecContext *enc = &ffenc->enc;
4432
    uint8_t *wptr;
4433
    mk_header(&hdr, enc, size);
4434
    wptr = http_fifo.wptr;
4435
    fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4436
    fifo_write(&http_fifo, buf, size, &wptr);
4437
    /* atomic modification of wptr */
4438
    http_fifo.wptr = wptr;
4439
    ffenc->data_count += size;
4440
    ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4441
}
4442
#endif
4443

    
4444
static void show_banner(void)
4445
{
4446
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4447
}
4448

    
4449
static void show_help(void)
4450
{
4451
    show_banner();
4452
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4453
           "Hyper fast multi format Audio/Video streaming server\n"
4454
           "\n"
4455
           "-L            : print the LICENSE\n"
4456
           "-h            : this help\n"
4457
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4458
           );
4459
}
4460

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

    
4481
static void handle_child_exit(int sig)
4482
{
4483
    pid_t pid;
4484
    int status;
4485

    
4486
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4487
        FFStream *feed;
4488

    
4489
        for (feed = first_feed; feed; feed = feed->next) {
4490
            if (feed->pid == pid) {
4491
                int uptime = time(0) - feed->pid_start;
4492

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

    
4496
                if (uptime < 30) {
4497
                    /* Turn off any more restarts */
4498
                    feed->child_argv = 0;
4499
                }
4500
            }
4501
        }
4502
    }
4503

    
4504
    need_to_start_children = 1;
4505
}
4506

    
4507
int main(int argc, char **argv)
4508
{
4509
    const char *config_filename;
4510
    int c;
4511
    struct sigaction sigact;
4512

    
4513
    av_register_all();
4514

    
4515
    config_filename = "/etc/ffserver.conf";
4516

    
4517
    my_program_name = argv[0];
4518
    my_program_dir = getcwd(0, 0);
4519
    ffserver_daemon = 1;
4520

    
4521
    for(;;) {
4522
        c = getopt(argc, argv, "ndLh?f:");
4523
        if (c == -1)
4524
            break;
4525
        switch(c) {
4526
        case 'L':
4527
            show_license();
4528
            exit(1);
4529
        case '?':
4530
        case 'h':
4531
            show_help();
4532
            exit(1);
4533
        case 'n':
4534
            no_launch = 1;
4535
            break;
4536
        case 'd':
4537
            ffserver_debug = 1;
4538
            ffserver_daemon = 0;
4539
            break;
4540
        case 'f':
4541
            config_filename = optarg;
4542
            break;
4543
        default:
4544
            exit(2);
4545
        }
4546
    }
4547

    
4548
    putenv("http_proxy");               /* Kill the http_proxy */
4549

    
4550
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4551

    
4552
    /* address on which the server will handle HTTP connections */
4553
    my_http_addr.sin_family = AF_INET;
4554
    my_http_addr.sin_port = htons (8080);
4555
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4556

    
4557
    /* address on which the server will handle RTSP connections */
4558
    my_rtsp_addr.sin_family = AF_INET;
4559
    my_rtsp_addr.sin_port = htons (5454);
4560
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4561

    
4562
    nb_max_connections = 5;
4563
    max_bandwidth = 1000;
4564
    first_stream = NULL;
4565
    logfilename[0] = '\0';
4566

    
4567
    memset(&sigact, 0, sizeof(sigact));
4568
    sigact.sa_handler = handle_child_exit;
4569
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4570
    sigaction(SIGCHLD, &sigact, 0);
4571

    
4572
    if (parse_ffconfig(config_filename) < 0) {
4573
        fprintf(stderr, "Incorrect config file - exiting.\n");
4574
        exit(1);
4575
    }
4576

    
4577
    build_file_streams();
4578

    
4579
    build_feed_streams();
4580

    
4581
    compute_bandwidth();
4582

    
4583
    /* put the process in background and detach it from its TTY */
4584
    if (ffserver_daemon) {
4585
        int pid;
4586

    
4587
        pid = fork();
4588
        if (pid < 0) {
4589
            perror("fork");
4590
            exit(1);
4591
        } else if (pid > 0) {
4592
            /* parent : exit */
4593
            exit(0);
4594
        } else {
4595
            /* child */
4596
            setsid();
4597
            chdir("/");
4598
            close(0);
4599
            open("/dev/null", O_RDWR);
4600
            if (strcmp(logfilename, "-") != 0) {
4601
                close(1);
4602
                dup(0);
4603
            }
4604
            close(2);
4605
            dup(0);
4606
        }
4607
    }
4608

    
4609
    /* signal init */
4610
    signal(SIGPIPE, SIG_IGN);
4611

    
4612
    /* open log file if needed */
4613
    if (logfilename[0] != '\0') {
4614
        if (!strcmp(logfilename, "-"))
4615
            logfile = stdout;
4616
        else
4617
            logfile = fopen(logfilename, "w");
4618
    }
4619

    
4620
    if (http_server() < 0) {
4621
        fprintf(stderr, "Could not start server\n");
4622
        exit(1);
4623
    }
4624

    
4625
    return 0;
4626
}