Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 087fa475

History | View | Annotate | Download (151 KB)

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

    
24
#include <stdarg.h>
25
#include <unistd.h>
26
#include <fcntl.h>
27
#include <sys/ioctl.h>
28
#ifdef HAVE_SYS_POLL_H
29
#include <sys/poll.h>
30
#endif
31
#include <errno.h>
32
#include <sys/time.h>
33
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
34
#include <time.h>
35
#include <sys/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
#undef exit
51

    
52
/* maximum number of simultaneous HTTP connections */
53
#define HTTP_MAX_CONNECTIONS 2000
54

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

    
65
    RTSPSTATE_WAIT_REQUEST,
66
    RTSPSTATE_SEND_REPLY,
67
    RTSPSTATE_SEND_PACKET,
68
};
69

    
70
const char *http_state[] = {
71
    "HTTP_WAIT_REQUEST",
72
    "HTTP_SEND_HEADER",
73

    
74
    "SEND_DATA_HEADER",
75
    "SEND_DATA",
76
    "SEND_DATA_TRAILER",
77
    "RECEIVE_DATA",
78
    "WAIT_FEED",
79
    "READY",
80

    
81
    "RTSP_WAIT_REQUEST",
82
    "RTSP_SEND_REPLY",
83
    "RTSP_SEND_PACKET",
84
};
85

    
86
#define IOBUFFER_INIT_SIZE 8192
87

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

    
92
#define SYNC_TIMEOUT (10 * 1000)
93

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

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

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

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

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

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

    
162
static AVFrame dummy_frame;
163

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

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

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

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

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

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

    
237
struct sockaddr_in my_http_addr;
238
struct sockaddr_in my_rtsp_addr;
239

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

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

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

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

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

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

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

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

    
286
static int nb_max_connections;
287
static int nb_connections;
288

    
289
static int max_bandwidth;
290
static int current_bandwidth;
291

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

    
294
static AVRandomState random_state;
295

    
296
static FILE *logfile = NULL;
297

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

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

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

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

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

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

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

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

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

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

    
361

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

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

    
371
            feed->pid = fork();
372

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

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

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

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

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

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

    
410
                signal(SIGPIPE, SIG_DFL);
411

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

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

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

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

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

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

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

    
449
    return server_fd;
450
}
451

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

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

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

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

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

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

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

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

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

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

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

    
524
    start_children(first_feed);
525

    
526
    first_http_ctx = NULL;
527
    nb_connections = 0;
528

    
529
    start_multicast();
530

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

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

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

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

    
599
        cur_time = av_gettime() / 1000;
600

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

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

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

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

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

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

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

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

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

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

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

    
679
    start_wait_request(c, is_rtsp);
680

    
681
    return;
682

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

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

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

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

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

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

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

    
747
    ctx = &c->fmt_ctx;
748

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
967
                q += 20;
968

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

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

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

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

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

    
994
        p++;
995
    }
996

    
997
    return 0;
998
}
999

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

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

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

    
1016
        /* Potential stream */
1017

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

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

    
1035
    return best;
1036
}
1037

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

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

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

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

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

    
1073
    return action_required;
1074
}
1075

    
1076

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1232
        p++;
1233
    }
1234

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

    
1254
    // "redirect" / request to index.html
1255
    if (!strlen(filename))
1256
        pstrcpy(filename, sizeof(filename) - 1, "index.html");
1257

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

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

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

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

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

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

    
1307
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1308
        current_bandwidth += stream->bandwidth;
1309
    }
1310

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

    
1323
        /* prepare output buffer */
1324
        c->buffer_ptr = c->buffer;
1325
        c->buffer_end = q;
1326
        c->state = HTTPSTATE_SEND_HEADER;
1327
        return 0;
1328
    }
1329

    
1330
    if (redir_type != REDIR_NONE) {
1331
        char *hostinfo = 0;
1332

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

    
1342
            p++;
1343
        }
1344

    
1345
        if (hostinfo) {
1346
            char *eoh;
1347
            char hostbuf[260];
1348

    
1349
            while (isspace(*hostinfo))
1350
                hostinfo++;
1351

    
1352
            eoh = strchr(hostinfo, '\n');
1353
            if (eoh) {
1354
                if (eoh[-1] == '\r')
1355
                    eoh--;
1356

    
1357
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1358
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1359
                    hostbuf[eoh - hostinfo] = 0;
1360

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

    
1413
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1414
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1415
                            q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1416

    
1417
                            len = sizeof(my_addr);
1418
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1419

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

    
1437
                    /* prepare output buffer */
1438
                    c->buffer_ptr = c->buffer;
1439
                    c->buffer_end = q;
1440
                    c->state = HTTPSTATE_SEND_HEADER;
1441
                    return 0;
1442
                }
1443
            }
1444
        }
1445

    
1446
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1447
        goto send_error;
1448
    }
1449

    
1450
    stream->conns_served++;
1451

    
1452
    /* XXX: add there authenticate and IP match */
1453

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

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

    
1475
                p++;
1476
            }
1477

    
1478
            if (logline) {
1479
                char *eol = strchr(logline, '\n');
1480

    
1481
                logline += 17;
1482

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

    
1491
#ifdef DEBUG_WMP
1492
            http_log("\nGot request:\n%s\n", c->buffer);
1493
#endif
1494

    
1495
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1496
                HTTPContext *wmpc;
1497

    
1498
                /* Now we have to find the client_id */
1499
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1500
                    if (wmpc->wmp_client_id == client_id)
1501
                        break;
1502
                }
1503

    
1504
                if (wmpc) {
1505
                    if (modify_current_stream(wmpc, ratebuf)) {
1506
                        wmpc->switch_pending = 1;
1507
                    }
1508
                }
1509
            }
1510

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

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

    
1530
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1531
        goto send_stats;
1532

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

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

    
1547
    /* for asf, we need extra headers */
1548
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1549
        /* Need to allocate a client id */
1550

    
1551
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1552

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

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

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

    
1588
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1589
{
1590
    static const char *suffix = " kMGTP";
1591
    const char *s;
1592

    
1593
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1594
    }
1595

    
1596
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1597
}
1598

    
1599
static void compute_stats(HTTPContext *c)
1600
{
1601
    HTTPContext *c1;
1602
    FFStream *stream;
1603
    char *p;
1604
    time_t ti;
1605
    int i, len;
1606
    ByteIOContext pb1, *pb = &pb1;
1607

    
1608
    if (url_open_dyn_buf(pb) < 0) {
1609
        /* XXX: return an error ? */
1610
        c->buffer_ptr = c->buffer;
1611
        c->buffer_end = c->buffer;
1612
        return;
1613
    }
1614

    
1615
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1616
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1617
    url_fprintf(pb, "Pragma: no-cache\r\n");
1618
    url_fprintf(pb, "\r\n");
1619

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

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

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

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

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

    
1728
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1729
                {
1730
                    FILE *pid_stat;
1731
                    char ps_cmd[64];
1732

    
1733
                    /* This is somewhat linux specific I guess */
1734
                    snprintf(ps_cmd, sizeof(ps_cmd),
1735
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1736
                             stream->pid);
1737

    
1738
                    pid_stat = popen(ps_cmd, "r");
1739
                    if (pid_stat) {
1740
                        char cpuperc[10];
1741
                        char cpuused[64];
1742

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

    
1753
                url_fprintf(pb, "<p>");
1754
            }
1755
            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");
1756

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

    
1763
                parameters[0] = 0;
1764

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

    
1783
        }
1784
        stream = stream->next;
1785
    }
1786

    
1787
#if 0
1788
    {
1789
        float avg;
1790
        AVCodecContext *enc;
1791
        char buf[1024];
1792

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

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

    
1817
    /* connection status */
1818
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1819

    
1820
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1821
                 nb_connections, nb_max_connections);
1822

    
1823
    url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1824
                 current_bandwidth, max_bandwidth);
1825

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

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

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

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

    
1872
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1873
    c->buffer_ptr = c->pb_buffer;
1874
    c->buffer_end = c->pb_buffer + len;
1875
}
1876

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

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

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

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

    
1928
#if 0
1929
    { time_t when = stream_pos / 1000000;
1930
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1931
    }
1932
#endif
1933

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

    
1942
    /* open each parser */
1943
    for(i=0;i<s->nb_streams;i++)
1944
        open_parser(s, i);
1945

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

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

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

    
1974
/* return the estimated time at which the current packet must be sent
1975
   (in us) */
1976
static int64_t get_packet_send_clock(HTTPContext *c)
1977
{
1978
    int bytes_left, bytes_sent, frame_bytes;
1979

    
1980
    frame_bytes = c->cur_frame_bytes;
1981
    if (frame_bytes <= 0) {
1982
        return c->cur_pts;
1983
    } else {
1984
        bytes_left = c->buffer_end - c->buffer_ptr;
1985
        bytes_sent = frame_bytes - bytes_left;
1986
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
1987
    }
1988
}
1989

    
1990

    
1991
static int http_prepare_data(HTTPContext *c)
1992
{
1993
    int i, len, ret;
1994
    AVFormatContext *ctx;
1995

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

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

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

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

    
2043
        av_set_parameters(&c->fmt_ctx, NULL);
2044
        if (av_write_header(&c->fmt_ctx) < 0)
2045
            return -1;
2046

    
2047
        len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2048
        c->buffer_ptr = c->pb_buffer;
2049
        c->buffer_end = c->pb_buffer + len;
2050

    
2051
        c->state = HTTPSTATE_SEND_DATA;
2052
        c->last_packet_sent = 0;
2053
        break;
2054
    case HTTPSTATE_SEND_DATA:
2055
        /* find a new packet */
2056
        {
2057
            AVPacket pkt;
2058

    
2059
            /* read a packet from the input stream */
2060
            if (c->stream->feed) {
2061
                ffm_set_write_index(c->fmt_in,
2062
                                    c->stream->feed->feed_write_index,
2063
                                    c->stream->feed->feed_size);
2064
            }
2065

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

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

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

    
2198
                        len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2199
                        c->cur_frame_bytes = len;
2200
                        c->buffer_ptr = c->pb_buffer;
2201
                        c->buffer_end = c->pb_buffer + len;
2202

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

    
2228
        c->last_packet_sent = 1;
2229
        break;
2230
    }
2231
    return 0;
2232
}
2233

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

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

    
2271
                c->data_count += len;
2272
                update_datarate(&c->datarate, c->data_count);
2273
                if (c->stream)
2274
                    c->stream->bytes_served += len;
2275

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

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

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

    
2360
static int http_start_receive_data(HTTPContext *c)
2361
{
2362
    int fd;
2363

    
2364
    if (c->stream->feed_opened)
2365
        return -1;
2366

    
2367
    /* Don't permit writing to this one */
2368
    if (c->stream->readonly)
2369
        return -1;
2370

    
2371
    /* open feed */
2372
    fd = open(c->stream->feed_filename, O_RDWR);
2373
    if (fd < 0)
2374
        return -1;
2375
    c->feed_fd = fd;
2376

    
2377
    c->stream->feed_write_index = ffm_read_write_index(fd);
2378
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2379
    lseek(fd, 0, SEEK_SET);
2380

    
2381
    /* init buffer input */
2382
    c->buffer_ptr = c->buffer;
2383
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2384
    c->stream->feed_opened = 1;
2385
    return 0;
2386
}
2387

    
2388
static int http_receive_data(HTTPContext *c)
2389
{
2390
    HTTPContext *c1;
2391

    
2392
    if (c->buffer_end > c->buffer_ptr) {
2393
        int len;
2394

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

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

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

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

    
2430
            feed->feed_write_index += FFM_PACKET_SIZE;
2431
            /* update file size */
2432
            if (feed->feed_write_index > c->stream->feed_size)
2433
                feed->feed_size = feed->feed_write_index;
2434

    
2435
            /* handle wrap around if max file size reached */
2436
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2437
                feed->feed_write_index = FFM_PACKET_SIZE;
2438

    
2439
            /* write index */
2440
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2441

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

    
2456
            memset(&s, 0, sizeof(s));
2457

    
2458
            url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2459
            pb->buf_end = c->buffer_end;        /* ?? */
2460
            pb->is_streamed = 1;
2461

    
2462
            /* use feed output format name to find corresponding input format */
2463
            fmt_in = av_find_input_format(feed->fmt->name);
2464
            if (!fmt_in)
2465
                goto fail;
2466

    
2467
            if (fmt_in->priv_data_size > 0) {
2468
                s.priv_data = av_mallocz(fmt_in->priv_data_size);
2469
                if (!s.priv_data)
2470
                    goto fail;
2471
            } else
2472
                s.priv_data = NULL;
2473

    
2474
            if (fmt_in->read_header(&s, 0) < 0) {
2475
                av_freep(&s.priv_data);
2476
                goto fail;
2477
            }
2478

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

    
2493
    return 0;
2494
 fail:
2495
    c->stream->feed_opened = 0;
2496
    close(c->feed_fd);
2497
    return -1;
2498
}
2499

    
2500
/********************************************************************/
2501
/* RTSP handling */
2502

    
2503
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2504
{
2505
    const char *str;
2506
    time_t ti;
2507
    char *p;
2508
    char buf2[32];
2509

    
2510
    switch(error_number) {
2511
#define DEF(n, c, s) case c: str = s; break;
2512
#include "rtspcodes.h"
2513
#undef DEF
2514
    default:
2515
        str = "Unknown Error";
2516
        break;
2517
    }
2518

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

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

    
2532
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2533
{
2534
    rtsp_reply_header(c, error_number);
2535
    url_fprintf(c->pb, "\r\n");
2536
}
2537

    
2538
static int rtsp_parse_request(HTTPContext *c)
2539
{
2540
    const char *p, *p1, *p2;
2541
    char cmd[32];
2542
    char url[1024];
2543
    char protocol[32];
2544
    char line[1024];
2545
    ByteIOContext pb1;
2546
    int len;
2547
    RTSPHeader header1, *header = &header1;
2548

    
2549
    c->buffer_ptr[0] = '\0';
2550
    p = c->buffer;
2551

    
2552
    get_word(cmd, sizeof(cmd), &p);
2553
    get_word(url, sizeof(url), &p);
2554
    get_word(protocol, sizeof(protocol), &p);
2555

    
2556
    pstrcpy(c->method, sizeof(c->method), cmd);
2557
    pstrcpy(c->url, sizeof(c->url), url);
2558
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2559

    
2560
    c->pb = &pb1;
2561
    if (url_open_dyn_buf(c->pb) < 0) {
2562
        /* XXX: cannot do more */
2563
        c->pb = NULL; /* safety */
2564
        return -1;
2565
    }
2566

    
2567
    /* check version name */
2568
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2569
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2570
        goto the_end;
2571
    }
2572

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

    
2599
    /* handle sequence number */
2600
    c->seq = header->seq;
2601

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

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

    
2640
    if (url_open_dyn_buf(pb) < 0)
2641
        return -1;
2642

    
2643
    /* general media info */
2644

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

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

    
2730
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2731
{
2732
    FFStream *stream;
2733
    char path1[1024];
2734
    const char *path;
2735
    uint8_t *content;
2736
    int content_length, len;
2737
    struct sockaddr_in my_addr;
2738

    
2739
    /* find which url is asked */
2740
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2741
    path = path1;
2742
    if (*path == '/')
2743
        path++;
2744

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

    
2755
 found:
2756
    /* prepare the media description in sdp format */
2757

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

    
2773
static HTTPContext *find_rtp_session(const char *session_id)
2774
{
2775
    HTTPContext *c;
2776

    
2777
    if (session_id[0] == '\0')
2778
        return NULL;
2779

    
2780
    for(c = first_http_ctx; c != NULL; c = c->next) {
2781
        if (!strcmp(c->session_id, session_id))
2782
            return c;
2783
    }
2784
    return NULL;
2785
}
2786

    
2787
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2788
{
2789
    RTSPTransportField *th;
2790
    int i;
2791

    
2792
    for(i=0;i<h->nb_transports;i++) {
2793
        th = &h->transports[i];
2794
        if (th->protocol == protocol)
2795
            return th;
2796
    }
2797
    return NULL;
2798
}
2799

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

    
2813
    /* find which url is asked */
2814
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2815
    path = path1;
2816
    if (*path == '/')
2817
        path++;
2818

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

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

    
2846
    /* generate session id if needed */
2847
    if (h->session_id[0] == '\0') {
2848
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2849
                 av_random(&random_state), av_random(&random_state));
2850
    }
2851

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

    
2865
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2866
                                   th->protocol);
2867
        if (!rtp_c) {
2868
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2869
            return;
2870
        }
2871

    
2872
        /* open input stream */
2873
        if (open_input_stream(rtp_c, "") < 0) {
2874
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2875
            return;
2876
        }
2877
    }
2878

    
2879
    /* test if stream is OK (test needed because several SETUP needs
2880
       to be done for a given file) */
2881
    if (rtp_c->stream != stream) {
2882
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2883
        return;
2884
    }
2885

    
2886
    /* test if stream is already set up */
2887
    if (rtp_c->rtp_ctx[stream_index]) {
2888
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2889
        return;
2890
    }
2891

    
2892
    /* check transport */
2893
    th = find_transport(h, rtp_c->rtp_protocol);
2894
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2895
                th->client_port_min <= 0)) {
2896
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2897
        return;
2898
    }
2899

    
2900
    /* setup default options */
2901
    setup.transport_option[0] = '\0';
2902
    dest_addr = rtp_c->from_addr;
2903
    dest_addr.sin_port = htons(th->client_port_min);
2904

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

    
2917
    /* setup stream */
2918
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2919
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2920
        return;
2921
    }
2922

    
2923
    /* now everything is OK, so we can send the connection parameters */
2924
    rtsp_reply_header(c, RTSP_STATUS_OK);
2925
    /* session ID */
2926
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2927

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

    
2948

    
2949
    url_fprintf(c->pb, "\r\n");
2950
}
2951

    
2952

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

    
2964
    rtp_c = find_rtp_session(session_id);
2965
    if (!rtp_c)
2966
        return NULL;
2967

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

    
2985
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2986
{
2987
    HTTPContext *rtp_c;
2988

    
2989
    rtp_c = find_rtp_session_with_url(url, h->session_id);
2990
    if (!rtp_c) {
2991
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
2992
        return;
2993
    }
2994

    
2995
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2996
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
2997
        rtp_c->state != HTTPSTATE_READY) {
2998
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2999
        return;
3000
    }
3001

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

    
3010
    rtp_c->state = HTTPSTATE_SEND_DATA;
3011

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

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

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

    
3029
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3030
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3031
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3032
        return;
3033
    }
3034

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

    
3044
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3045
{
3046
    HTTPContext *rtp_c;
3047

    
3048
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3049
    if (!rtp_c) {
3050
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3051
        return;
3052
    }
3053

    
3054
    /* abort the session */
3055
    close_connection(rtp_c);
3056

    
3057
    if (ff_rtsp_callback) {
3058
        ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id,
3059
                         NULL, 0,
3060
                         rtp_c->stream->rtsp_option);
3061
    }
3062

    
3063
    /* now everything is OK, so we can send the connection parameters */
3064
    rtsp_reply_header(c, RTSP_STATUS_OK);
3065
    /* session ID */
3066
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3067
    url_fprintf(c->pb, "\r\n");
3068
}
3069

    
3070

    
3071
/********************************************************************/
3072
/* RTP handling */
3073

    
3074
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3075
                                       FFStream *stream, const char *session_id,
3076
                                       enum RTSPProtocol rtp_protocol)
3077
{
3078
    HTTPContext *c = NULL;
3079
    const char *proto_str;
3080

    
3081
    /* XXX: should output a warning page when coming
3082
       close to the connection limit */
3083
    if (nb_connections >= nb_max_connections)
3084
        goto fail;
3085

    
3086
    /* add a new connection */
3087
    c = av_mallocz(sizeof(HTTPContext));
3088
    if (!c)
3089
        goto fail;
3090

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

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

    
3123
    current_bandwidth += stream->bandwidth;
3124

    
3125
    c->next = first_http_ctx;
3126
    first_http_ctx = c;
3127
    return c;
3128

    
3129
 fail:
3130
    if (c) {
3131
        av_free(c->buffer);
3132
        av_free(c);
3133
    }
3134
    return NULL;
3135
}
3136

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

    
3152
    /* now we can open the relevant output stream */
3153
    ctx = av_alloc_format_context();
3154
    if (!ctx)
3155
        return -1;
3156
    ctx->oformat = &rtp_muxer;
3157

    
3158
    st = av_mallocz(sizeof(AVStream));
3159
    if (!st)
3160
        goto fail;
3161
    st->codec= avcodec_alloc_context();
3162
    ctx->nb_streams = 1;
3163
    ctx->streams[0] = st;
3164

    
3165
    if (!c->stream->feed ||
3166
        c->stream->feed == c->stream) {
3167
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3168
    } else {
3169
        memcpy(st,
3170
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3171
               sizeof(AVStream));
3172
    }
3173

    
3174
    /* build destination RTP address */
3175
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3176

    
3177
    switch(c->rtp_protocol) {
3178
    case RTSP_PROTOCOL_RTP_UDP:
3179
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3180
        /* RTP/UDP case */
3181

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

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

    
3210
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3211
             ipaddr, ntohs(dest_addr->sin_port),
3212
             ctime1(buf2),
3213
             c->stream->filename, stream_index, c->protocol);
3214

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

    
3231
    c->rtp_ctx[stream_index] = ctx;
3232
    return 0;
3233
}
3234

    
3235
/********************************************************************/
3236
/* ffserver initialization */
3237

    
3238
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3239
{
3240
    AVStream *fst;
3241

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

    
3255
/* return the stream number in the feed */
3256
static int add_av_stream(FFStream *feed, AVStream *st)
3257
{
3258
    AVStream *fst;
3259
    AVCodecContext *av, *av1;
3260
    int i;
3261

    
3262
    av = st->codec;
3263
    for(i=0;i<feed->nb_streams;i++) {
3264
        st = feed->streams[i];
3265
        av1 = st->codec;
3266
        if (av1->codec_id == av->codec_id &&
3267
            av1->codec_type == av->codec_type &&
3268
            av1->bit_rate == av->bit_rate) {
3269

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

    
3290
    fst = add_av_stream1(feed, av);
3291
    if (!fst)
3292
        return -1;
3293
    return feed->nb_streams - 1;
3294
 found:
3295
    return i;
3296
}
3297

    
3298
static void remove_stream(FFStream *stream)
3299
{
3300
    FFStream **ps;
3301
    ps = &first_stream;
3302
    while (*ps != NULL) {
3303
        if (*ps == stream) {
3304
            *ps = (*ps)->next;
3305
        } else {
3306
            ps = &(*ps)->next;
3307
        }
3308
    }
3309
}
3310

    
3311
/* specific mpeg4 handling : we extract the raw parameters */
3312
static void extract_mpeg4_header(AVFormatContext *infile)
3313
{
3314
    int mpeg4_count, i, size;
3315
    AVPacket pkt;
3316
    AVStream *st;
3317
    const uint8_t *p;
3318

    
3319
    mpeg4_count = 0;
3320
    for(i=0;i<infile->nb_streams;i++) {
3321
        st = infile->streams[i];
3322
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3323
            st->codec->extradata_size == 0) {
3324
            mpeg4_count++;
3325
        }
3326
    }
3327
    if (!mpeg4_count)
3328
        return;
3329

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

    
3360
/* compute the needed AVStream for each file */
3361
static void build_file_streams(void)
3362
{
3363
    FFStream *stream, *stream_next;
3364
    AVFormatContext *infile;
3365
    int i;
3366

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

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

    
3400
                for(i=0;i<infile->nb_streams;i++) {
3401
                    add_av_stream1(stream, infile->streams[i]->codec);
3402
                }
3403
                av_close_input_file(infile);
3404
            }
3405
        }
3406
    }
3407
}
3408

    
3409
/* compute the needed AVStream for each feed */
3410
static void build_feed_streams(void)
3411
{
3412
    FFStream *stream, *feed;
3413
    int i;
3414

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

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

    
3440
    /* create feed files if needed */
3441
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3442
        int fd;
3443

    
3444
        if (url_exist(feed->feed_filename)) {
3445
            /* See if it matches */
3446
            AVFormatContext *s;
3447
            int matches = 0;
3448

    
3449
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3450
                /* Now see if it matches */
3451
                if (s->nb_streams == feed->nb_streams) {
3452
                    matches = 1;
3453
                    for(i=0;i<s->nb_streams;i++) {
3454
                        AVStream *sf, *ss;
3455
                        sf = feed->streams[i];
3456
                        ss = s->streams[i];
3457

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

    
3466
                            ccf = sf->codec;
3467
                            ccs = ss->codec;
3468
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3469

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

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

    
3522
            if (feed->readonly) {
3523
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3524
                    feed->feed_filename);
3525
                exit(1);
3526
            }
3527

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

    
3558
        feed->feed_write_index = ffm_read_write_index(fd);
3559
        feed->feed_size = lseek(fd, 0, SEEK_END);
3560
        /* ensure that we do not wrap before the end of file */
3561
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3562
            feed->feed_max_size = feed->feed_size;
3563

    
3564
        close(fd);
3565
    }
3566
}
3567

    
3568
/* compute the bandwidth used by each stream */
3569
static void compute_bandwidth(void)
3570
{
3571
    int bandwidth, i;
3572
    FFStream *stream;
3573

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

    
3591
static void get_arg(char *buf, int buf_size, const char **pp)
3592
{
3593
    const char *p;
3594
    char *q;
3595
    int quote;
3596

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

    
3623
/* add a codec and set the default parameters */
3624
static void add_codec(FFStream *stream, AVCodecContext *av)
3625
{
3626
    AVStream *st;
3627

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

    
3661
        if (!av->nsse_weight)
3662
            av->nsse_weight = 8;
3663

    
3664
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3665
        av->me_method = ME_EPZS;
3666
        av->rc_buffer_aggressivity = 1.0;
3667

    
3668
        if (!av->rc_eq)
3669
            av->rc_eq = "tex^qComp";
3670
        if (!av->i_quant_factor)
3671
            av->i_quant_factor = -0.8;
3672
        if (!av->b_quant_factor)
3673
            av->b_quant_factor = 1.25;
3674
        if (!av->b_quant_offset)
3675
            av->b_quant_offset = 1.25;
3676
        if (!av->rc_max_rate)
3677
            av->rc_max_rate = av->bit_rate * 2;
3678

    
3679
        if (av->rc_max_rate && !av->rc_buffer_size) {
3680
            av->rc_buffer_size = av->rc_max_rate;
3681
        }
3682

    
3683

    
3684
        break;
3685
    default:
3686
        av_abort();
3687
    }
3688

    
3689
    st = av_mallocz(sizeof(AVStream));
3690
    if (!st)
3691
        return;
3692
    st->codec = avcodec_alloc_context();
3693
    stream->streams[stream->nb_streams++] = st;
3694
    memcpy(st->codec, av, sizeof(AVCodecContext));
3695
}
3696

    
3697
static int opt_audio_codec(const char *arg)
3698
{
3699
    AVCodec *p;
3700

    
3701
    p = first_avcodec;
3702
    while (p) {
3703
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3704
            break;
3705
        p = p->next;
3706
    }
3707
    if (p == NULL) {
3708
        return CODEC_ID_NONE;
3709
    }
3710

    
3711
    return p->id;
3712
}
3713

    
3714
static int opt_video_codec(const char *arg)
3715
{
3716
    AVCodec *p;
3717

    
3718
    p = first_avcodec;
3719
    while (p) {
3720
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3721
            break;
3722
        p = p->next;
3723
    }
3724
    if (p == NULL) {
3725
        return CODEC_ID_NONE;
3726
    }
3727

    
3728
    return p->id;
3729
}
3730

    
3731
/* simplistic plugin support */
3732

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

    
3745
    init_func = dlsym(dll, "ffserver_module_init");
3746
    if (!init_func) {
3747
        fprintf(stderr,
3748
                "%s: init function 'ffserver_module_init()' not found\n",
3749
                filename);
3750
        dlclose(dll);
3751
    }
3752

    
3753
    init_func();
3754
}
3755
#endif
3756

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

    
3770
    f = fopen(filename, "r");
3771
    if (!f) {
3772
        perror(filename);
3773
        return -1;
3774
    }
3775

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

    
3797
        get_arg(cmd, sizeof(cmd), &p);
3798

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

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

    
3875
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3876

    
3877
                for (i = 0; i < 62; i++) {
3878
                    char argbuf[256];
3879

    
3880
                    get_arg(argbuf, sizeof(argbuf), &p);
3881
                    if (!argbuf[0])
3882
                        break;
3883

    
3884
                    feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3885
                    strcpy(feed->child_argv[i], argbuf);
3886
                }
3887

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

    
3890
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3891
                    "http://%s:%d/%s",
3892
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3893
                    inet_ntoa(my_http_addr.sin_addr),
3894
                    ntohs(my_http_addr.sin_port), feed->filename);
3895

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

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

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

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

    
4105
                get_arg(arg, sizeof(arg), &p);
4106

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

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

    
4268
            get_arg(arg, sizeof(arg), &p);
4269

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

    
4281
            get_arg(arg, sizeof(arg), &p);
4282

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

    
4295
            if (!errors) {
4296
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4297
                IPAddressACL **naclp = 0;
4298

    
4299
                *nacl = acl;
4300
                nacl->next = 0;
4301

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

    
4312
                if (naclp) {
4313
                    while (*naclp)
4314
                        naclp = &(*naclp)->next;
4315

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

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

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

    
4426
static void show_banner(void)
4427
{
4428
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4429
}
4430

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

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

    
4463
static void handle_child_exit(int sig)
4464
{
4465
    pid_t pid;
4466
    int status;
4467

    
4468
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4469
        FFStream *feed;
4470

    
4471
        for (feed = first_feed; feed; feed = feed->next) {
4472
            if (feed->pid == pid) {
4473
                int uptime = time(0) - feed->pid_start;
4474

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

    
4478
                if (uptime < 30) {
4479
                    /* Turn off any more restarts */
4480
                    feed->child_argv = 0;
4481
                }
4482
            }
4483
        }
4484
    }
4485

    
4486
    need_to_start_children = 1;
4487
}
4488

    
4489
int main(int argc, char **argv)
4490
{
4491
    const char *config_filename;
4492
    int c;
4493
    struct sigaction sigact;
4494

    
4495
    av_register_all();
4496

    
4497
    config_filename = "/etc/ffserver.conf";
4498

    
4499
    my_program_name = argv[0];
4500
    my_program_dir = getcwd(0, 0);
4501
    ffserver_daemon = 1;
4502

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

    
4530
    putenv("http_proxy");               /* Kill the http_proxy */
4531

    
4532
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4533

    
4534
    /* address on which the server will handle HTTP connections */
4535
    my_http_addr.sin_family = AF_INET;
4536
    my_http_addr.sin_port = htons (8080);
4537
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4538

    
4539
    /* address on which the server will handle RTSP connections */
4540
    my_rtsp_addr.sin_family = AF_INET;
4541
    my_rtsp_addr.sin_port = htons (5454);
4542
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4543

    
4544
    nb_max_connections = 5;
4545
    max_bandwidth = 1000;
4546
    first_stream = NULL;
4547
    logfilename[0] = '\0';
4548

    
4549
    memset(&sigact, 0, sizeof(sigact));
4550
    sigact.sa_handler = handle_child_exit;
4551
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4552
    sigaction(SIGCHLD, &sigact, 0);
4553

    
4554
    if (parse_ffconfig(config_filename) < 0) {
4555
        fprintf(stderr, "Incorrect config file - exiting.\n");
4556
        exit(1);
4557
    }
4558

    
4559
    build_file_streams();
4560

    
4561
    build_feed_streams();
4562

    
4563
    compute_bandwidth();
4564

    
4565
    /* put the process in background and detach it from its TTY */
4566
    if (ffserver_daemon) {
4567
        int pid;
4568

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

    
4591
    /* signal init */
4592
    signal(SIGPIPE, SIG_IGN);
4593

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

    
4602
    if (http_server() < 0) {
4603
        fprintf(stderr, "Could not start server\n");
4604
        exit(1);
4605
    }
4606

    
4607
    return 0;
4608
}