Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 2bd8416e

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
static struct sockaddr_in my_http_addr;
238
static 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 = 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
    case RTSP_STATUS_OK:
2512
        str = "OK";
2513
        break;
2514
    case RTSP_STATUS_METHOD:
2515
        str = "Method Not Allowed";
2516
        break;
2517
    case RTSP_STATUS_BANDWIDTH:
2518
        str = "Not Enough Bandwidth";
2519
        break;
2520
    case RTSP_STATUS_SESSION:
2521
        str = "Session Not Found";
2522
        break;
2523
    case RTSP_STATUS_STATE:
2524
        str = "Method Not Valid in This State";
2525
        break;
2526
    case RTSP_STATUS_AGGREGATE:
2527
        str = "Aggregate operation not allowed";
2528
        break;
2529
    case RTSP_STATUS_ONLY_AGGREGATE:
2530
        str = "Only aggregate operation allowed";
2531
        break;
2532
    case RTSP_STATUS_TRANSPORT:
2533
        str = "Unsupported transport";
2534
        break;
2535
    case RTSP_STATUS_INTERNAL:
2536
        str = "Internal Server Error";
2537
        break;
2538
    case RTSP_STATUS_SERVICE:
2539
        str = "Service Unavailable";
2540
        break;
2541
    case RTSP_STATUS_VERSION:
2542
        str = "RTSP Version not supported";
2543
        break;
2544
    default:
2545
        str = "Unknown Error";
2546
        break;
2547
    }
2548

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

    
2552
    /* output GMT time */
2553
    ti = time(NULL);
2554
    p = ctime(&ti);
2555
    strcpy(buf2, p);
2556
    p = buf2 + strlen(p) - 1;
2557
    if (*p == '\n')
2558
        *p = '\0';
2559
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2560
}
2561

    
2562
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2563
{
2564
    rtsp_reply_header(c, error_number);
2565
    url_fprintf(c->pb, "\r\n");
2566
}
2567

    
2568
static int rtsp_parse_request(HTTPContext *c)
2569
{
2570
    const char *p, *p1, *p2;
2571
    char cmd[32];
2572
    char url[1024];
2573
    char protocol[32];
2574
    char line[1024];
2575
    ByteIOContext pb1;
2576
    int len;
2577
    RTSPHeader header1, *header = &header1;
2578

    
2579
    c->buffer_ptr[0] = '\0';
2580
    p = c->buffer;
2581

    
2582
    get_word(cmd, sizeof(cmd), &p);
2583
    get_word(url, sizeof(url), &p);
2584
    get_word(protocol, sizeof(protocol), &p);
2585

    
2586
    pstrcpy(c->method, sizeof(c->method), cmd);
2587
    pstrcpy(c->url, sizeof(c->url), url);
2588
    pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2589

    
2590
    c->pb = &pb1;
2591
    if (url_open_dyn_buf(c->pb) < 0) {
2592
        /* XXX: cannot do more */
2593
        c->pb = NULL; /* safety */
2594
        return -1;
2595
    }
2596

    
2597
    /* check version name */
2598
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2599
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2600
        goto the_end;
2601
    }
2602

    
2603
    /* parse each header line */
2604
    memset(header, 0, sizeof(RTSPHeader));
2605
    /* skip to next line */
2606
    while (*p != '\n' && *p != '\0')
2607
        p++;
2608
    if (*p == '\n')
2609
        p++;
2610
    while (*p != '\0') {
2611
        p1 = strchr(p, '\n');
2612
        if (!p1)
2613
            break;
2614
        p2 = p1;
2615
        if (p2 > p && p2[-1] == '\r')
2616
            p2--;
2617
        /* skip empty line */
2618
        if (p2 == p)
2619
            break;
2620
        len = p2 - p;
2621
        if (len > sizeof(line) - 1)
2622
            len = sizeof(line) - 1;
2623
        memcpy(line, p, len);
2624
        line[len] = '\0';
2625
        rtsp_parse_line(header, line);
2626
        p = p1 + 1;
2627
    }
2628

    
2629
    /* handle sequence number */
2630
    c->seq = header->seq;
2631

    
2632
    if (!strcmp(cmd, "DESCRIBE")) {
2633
        rtsp_cmd_describe(c, url);
2634
    } else if (!strcmp(cmd, "OPTIONS")) {
2635
        rtsp_cmd_options(c, url);
2636
    } else if (!strcmp(cmd, "SETUP")) {
2637
        rtsp_cmd_setup(c, url, header);
2638
    } else if (!strcmp(cmd, "PLAY")) {
2639
        rtsp_cmd_play(c, url, header);
2640
    } else if (!strcmp(cmd, "PAUSE")) {
2641
        rtsp_cmd_pause(c, url, header);
2642
    } else if (!strcmp(cmd, "TEARDOWN")) {
2643
        rtsp_cmd_teardown(c, url, header);
2644
    } else {
2645
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2646
    }
2647
 the_end:
2648
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2649
    c->pb = NULL; /* safety */
2650
    if (len < 0) {
2651
        /* XXX: cannot do more */
2652
        return -1;
2653
    }
2654
    c->buffer_ptr = c->pb_buffer;
2655
    c->buffer_end = c->pb_buffer + len;
2656
    c->state = RTSPSTATE_SEND_REPLY;
2657
    return 0;
2658
}
2659

    
2660
/* XXX: move that to rtsp.c, but would need to replace FFStream by
2661
   AVFormatContext */
2662
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2663
                                   struct in_addr my_ip)
2664
{
2665
    ByteIOContext pb1, *pb = &pb1;
2666
    int i, payload_type, port, private_payload_type, j;
2667
    const char *ipstr, *title, *mediatype;
2668
    AVStream *st;
2669

    
2670
    if (url_open_dyn_buf(pb) < 0)
2671
        return -1;
2672

    
2673
    /* general media info */
2674

    
2675
    url_fprintf(pb, "v=0\n");
2676
    ipstr = inet_ntoa(my_ip);
2677
    url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2678
    title = stream->title;
2679
    if (title[0] == '\0')
2680
        title = "No Title";
2681
    url_fprintf(pb, "s=%s\n", title);
2682
    if (stream->comment[0] != '\0')
2683
        url_fprintf(pb, "i=%s\n", stream->comment);
2684
    if (stream->is_multicast) {
2685
        url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2686
    }
2687
    /* for each stream, we output the necessary info */
2688
    private_payload_type = RTP_PT_PRIVATE;
2689
    for(i = 0; i < stream->nb_streams; i++) {
2690
        st = stream->streams[i];
2691
        if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2692
            mediatype = "video";
2693
        } else {
2694
            switch(st->codec->codec_type) {
2695
            case CODEC_TYPE_AUDIO:
2696
                mediatype = "audio";
2697
                break;
2698
            case CODEC_TYPE_VIDEO:
2699
                mediatype = "video";
2700
                break;
2701
            default:
2702
                mediatype = "application";
2703
                break;
2704
            }
2705
        }
2706
        /* NOTE: the port indication is not correct in case of
2707
           unicast. It is not an issue because RTSP gives it */
2708
        payload_type = rtp_get_payload_type(st->codec);
2709
        if (payload_type < 0)
2710
            payload_type = private_payload_type++;
2711
        if (stream->is_multicast) {
2712
            port = stream->multicast_port + 2 * i;
2713
        } else {
2714
            port = 0;
2715
        }
2716
        url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
2717
                    mediatype, port, payload_type);
2718
        if (payload_type >= RTP_PT_PRIVATE) {
2719
            /* for private payload type, we need to give more info */
2720
            switch(st->codec->codec_id) {
2721
            case CODEC_ID_MPEG4:
2722
                {
2723
                    uint8_t *data;
2724
                    url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
2725
                                payload_type, 90000);
2726
                    /* we must also add the mpeg4 header */
2727
                    data = st->codec->extradata;
2728
                    if (data) {
2729
                        url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2730
                        for(j=0;j<st->codec->extradata_size;j++) {
2731
                            url_fprintf(pb, "%02x", data[j]);
2732
                        }
2733
                        url_fprintf(pb, "\n");
2734
                    }
2735
                }
2736
                break;
2737
            default:
2738
                /* XXX: add other codecs ? */
2739
                goto fail;
2740
            }
2741
        }
2742
        url_fprintf(pb, "a=control:streamid=%d\n", i);
2743
    }
2744
    return url_close_dyn_buf(pb, pbuffer);
2745
 fail:
2746
    url_close_dyn_buf(pb, pbuffer);
2747
    av_free(*pbuffer);
2748
    return -1;
2749
}
2750

    
2751
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2752
{
2753
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2754
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2755
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2756
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2757
    url_fprintf(c->pb, "\r\n");
2758
}
2759

    
2760
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2761
{
2762
    FFStream *stream;
2763
    char path1[1024];
2764
    const char *path;
2765
    uint8_t *content;
2766
    int content_length, len;
2767
    struct sockaddr_in my_addr;
2768

    
2769
    /* find which url is asked */
2770
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2771
    path = path1;
2772
    if (*path == '/')
2773
        path++;
2774

    
2775
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2776
        if (!stream->is_feed && stream->fmt == &rtp_muxer &&
2777
            !strcmp(path, stream->filename)) {
2778
            goto found;
2779
        }
2780
    }
2781
    /* no stream found */
2782
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2783
    return;
2784

    
2785
 found:
2786
    /* prepare the media description in sdp format */
2787

    
2788
    /* get the host IP */
2789
    len = sizeof(my_addr);
2790
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2791
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2792
    if (content_length < 0) {
2793
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2794
        return;
2795
    }
2796
    rtsp_reply_header(c, RTSP_STATUS_OK);
2797
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2798
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2799
    url_fprintf(c->pb, "\r\n");
2800
    put_buffer(c->pb, content, content_length);
2801
}
2802

    
2803
static HTTPContext *find_rtp_session(const char *session_id)
2804
{
2805
    HTTPContext *c;
2806

    
2807
    if (session_id[0] == '\0')
2808
        return NULL;
2809

    
2810
    for(c = first_http_ctx; c != NULL; c = c->next) {
2811
        if (!strcmp(c->session_id, session_id))
2812
            return c;
2813
    }
2814
    return NULL;
2815
}
2816

    
2817
static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2818
{
2819
    RTSPTransportField *th;
2820
    int i;
2821

    
2822
    for(i=0;i<h->nb_transports;i++) {
2823
        th = &h->transports[i];
2824
        if (th->protocol == protocol)
2825
            return th;
2826
    }
2827
    return NULL;
2828
}
2829

    
2830
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2831
                           RTSPHeader *h)
2832
{
2833
    FFStream *stream;
2834
    int stream_index, port;
2835
    char buf[1024];
2836
    char path1[1024];
2837
    const char *path;
2838
    HTTPContext *rtp_c;
2839
    RTSPTransportField *th;
2840
    struct sockaddr_in dest_addr;
2841
    RTSPActionServerSetup setup;
2842

    
2843
    /* find which url is asked */
2844
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2845
    path = path1;
2846
    if (*path == '/')
2847
        path++;
2848

    
2849
    /* now check each stream */
2850
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2851
        if (!stream->is_feed && stream->fmt == &rtp_muxer) {
2852
            /* accept aggregate filenames only if single stream */
2853
            if (!strcmp(path, stream->filename)) {
2854
                if (stream->nb_streams != 1) {
2855
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2856
                    return;
2857
                }
2858
                stream_index = 0;
2859
                goto found;
2860
            }
2861

    
2862
            for(stream_index = 0; stream_index < stream->nb_streams;
2863
                stream_index++) {
2864
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2865
                         stream->filename, stream_index);
2866
                if (!strcmp(path, buf))
2867
                    goto found;
2868
            }
2869
        }
2870
    }
2871
    /* no stream found */
2872
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2873
    return;
2874
 found:
2875

    
2876
    /* generate session id if needed */
2877
    if (h->session_id[0] == '\0') {
2878
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2879
                 av_random(&random_state), av_random(&random_state));
2880
    }
2881

    
2882
    /* find rtp session, and create it if none found */
2883
    rtp_c = find_rtp_session(h->session_id);
2884
    if (!rtp_c) {
2885
        /* always prefer UDP */
2886
        th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2887
        if (!th) {
2888
            th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2889
            if (!th) {
2890
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2891
                return;
2892
            }
2893
        }
2894

    
2895
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2896
                                   th->protocol);
2897
        if (!rtp_c) {
2898
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2899
            return;
2900
        }
2901

    
2902
        /* open input stream */
2903
        if (open_input_stream(rtp_c, "") < 0) {
2904
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2905
            return;
2906
        }
2907
    }
2908

    
2909
    /* test if stream is OK (test needed because several SETUP needs
2910
       to be done for a given file) */
2911
    if (rtp_c->stream != stream) {
2912
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2913
        return;
2914
    }
2915

    
2916
    /* test if stream is already set up */
2917
    if (rtp_c->rtp_ctx[stream_index]) {
2918
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2919
        return;
2920
    }
2921

    
2922
    /* check transport */
2923
    th = find_transport(h, rtp_c->rtp_protocol);
2924
    if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2925
                th->client_port_min <= 0)) {
2926
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2927
        return;
2928
    }
2929

    
2930
    /* setup default options */
2931
    setup.transport_option[0] = '\0';
2932
    dest_addr = rtp_c->from_addr;
2933
    dest_addr.sin_port = htons(th->client_port_min);
2934

    
2935
    /* setup stream */
2936
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2937
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2938
        return;
2939
    }
2940

    
2941
    /* now everything is OK, so we can send the connection parameters */
2942
    rtsp_reply_header(c, RTSP_STATUS_OK);
2943
    /* session ID */
2944
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2945

    
2946
    switch(rtp_c->rtp_protocol) {
2947
    case RTSP_PROTOCOL_RTP_UDP:
2948
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2949
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2950
                    "client_port=%d-%d;server_port=%d-%d",
2951
                    th->client_port_min, th->client_port_min + 1,
2952
                    port, port + 1);
2953
        break;
2954
    case RTSP_PROTOCOL_RTP_TCP:
2955
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2956
                    stream_index * 2, stream_index * 2 + 1);
2957
        break;
2958
    default:
2959
        break;
2960
    }
2961
    if (setup.transport_option[0] != '\0') {
2962
        url_fprintf(c->pb, ";%s", setup.transport_option);
2963
    }
2964
    url_fprintf(c->pb, "\r\n");
2965

    
2966

    
2967
    url_fprintf(c->pb, "\r\n");
2968
}
2969

    
2970

    
2971
/* find an rtp connection by using the session ID. Check consistency
2972
   with filename */
2973
static HTTPContext *find_rtp_session_with_url(const char *url,
2974
                                              const char *session_id)
2975
{
2976
    HTTPContext *rtp_c;
2977
    char path1[1024];
2978
    const char *path;
2979
    char buf[1024];
2980
    int s;
2981

    
2982
    rtp_c = find_rtp_session(session_id);
2983
    if (!rtp_c)
2984
        return NULL;
2985

    
2986
    /* find which url is asked */
2987
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2988
    path = path1;
2989
    if (*path == '/')
2990
        path++;
2991
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2992
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2993
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
2994
        rtp_c->stream->filename, s);
2995
      if(!strncmp(path, buf, sizeof(buf))) {
2996
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2997
        return rtp_c;
2998
      }
2999
    }
3000
    return NULL;
3001
}
3002

    
3003
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3004
{
3005
    HTTPContext *rtp_c;
3006

    
3007
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3008
    if (!rtp_c) {
3009
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3010
        return;
3011
    }
3012

    
3013
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3014
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3015
        rtp_c->state != HTTPSTATE_READY) {
3016
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3017
        return;
3018
    }
3019

    
3020
#if 0
3021
    /* XXX: seek in stream */
3022
    if (h->range_start != AV_NOPTS_VALUE) {
3023
        printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3024
        av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3025
    }
3026
#endif
3027

    
3028
    rtp_c->state = HTTPSTATE_SEND_DATA;
3029

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

    
3037
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3038
{
3039
    HTTPContext *rtp_c;
3040

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

    
3047
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3048
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3049
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3050
        return;
3051
    }
3052

    
3053
    rtp_c->state = HTTPSTATE_READY;
3054
    rtp_c->first_pts = AV_NOPTS_VALUE;
3055
    /* now everything is OK, so we can send the connection parameters */
3056
    rtsp_reply_header(c, RTSP_STATUS_OK);
3057
    /* session ID */
3058
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3059
    url_fprintf(c->pb, "\r\n");
3060
}
3061

    
3062
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3063
{
3064
    HTTPContext *rtp_c;
3065
    char session_id[32];
3066

    
3067
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3068
    if (!rtp_c) {
3069
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3070
        return;
3071
    }
3072

    
3073
    pstrcpy(session_id, sizeof(session_id), rtp_c->session_id);
3074

    
3075
    /* abort the session */
3076
    close_connection(rtp_c);
3077

    
3078
    /* now everything is OK, so we can send the connection parameters */
3079
    rtsp_reply_header(c, RTSP_STATUS_OK);
3080
    /* session ID */
3081
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3082
    url_fprintf(c->pb, "\r\n");
3083
}
3084

    
3085

    
3086
/********************************************************************/
3087
/* RTP handling */
3088

    
3089
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3090
                                       FFStream *stream, const char *session_id,
3091
                                       enum RTSPProtocol rtp_protocol)
3092
{
3093
    HTTPContext *c = NULL;
3094
    const char *proto_str;
3095

    
3096
    /* XXX: should output a warning page when coming
3097
       close to the connection limit */
3098
    if (nb_connections >= nb_max_connections)
3099
        goto fail;
3100

    
3101
    /* add a new connection */
3102
    c = av_mallocz(sizeof(HTTPContext));
3103
    if (!c)
3104
        goto fail;
3105

    
3106
    c->fd = -1;
3107
    c->poll_entry = NULL;
3108
    c->from_addr = *from_addr;
3109
    c->buffer_size = IOBUFFER_INIT_SIZE;
3110
    c->buffer = av_malloc(c->buffer_size);
3111
    if (!c->buffer)
3112
        goto fail;
3113
    nb_connections++;
3114
    c->stream = stream;
3115
    pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3116
    c->state = HTTPSTATE_READY;
3117
    c->is_packetized = 1;
3118
    c->rtp_protocol = rtp_protocol;
3119

    
3120
    /* protocol is shown in statistics */
3121
    switch(c->rtp_protocol) {
3122
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3123
        proto_str = "MCAST";
3124
        break;
3125
    case RTSP_PROTOCOL_RTP_UDP:
3126
        proto_str = "UDP";
3127
        break;
3128
    case RTSP_PROTOCOL_RTP_TCP:
3129
        proto_str = "TCP";
3130
        break;
3131
    default:
3132
        proto_str = "???";
3133
        break;
3134
    }
3135
    pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3136
    pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3137

    
3138
    current_bandwidth += stream->bandwidth;
3139

    
3140
    c->next = first_http_ctx;
3141
    first_http_ctx = c;
3142
    return c;
3143

    
3144
 fail:
3145
    if (c) {
3146
        av_free(c->buffer);
3147
        av_free(c);
3148
    }
3149
    return NULL;
3150
}
3151

    
3152
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3153
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3154
   used. */
3155
static int rtp_new_av_stream(HTTPContext *c,
3156
                             int stream_index, struct sockaddr_in *dest_addr,
3157
                             HTTPContext *rtsp_c)
3158
{
3159
    AVFormatContext *ctx;
3160
    AVStream *st;
3161
    char *ipaddr;
3162
    URLContext *h;
3163
    uint8_t *dummy_buf;
3164
    char buf2[32];
3165
    int max_packet_size;
3166

    
3167
    /* now we can open the relevant output stream */
3168
    ctx = av_alloc_format_context();
3169
    if (!ctx)
3170
        return -1;
3171
    ctx->oformat = &rtp_muxer;
3172

    
3173
    st = av_mallocz(sizeof(AVStream));
3174
    if (!st)
3175
        goto fail;
3176
    st->codec= avcodec_alloc_context();
3177
    ctx->nb_streams = 1;
3178
    ctx->streams[0] = st;
3179

    
3180
    if (!c->stream->feed ||
3181
        c->stream->feed == c->stream) {
3182
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3183
    } else {
3184
        memcpy(st,
3185
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3186
               sizeof(AVStream));
3187
    }
3188
    st->priv_data = NULL;
3189

    
3190
    /* build destination RTP address */
3191
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3192

    
3193
    switch(c->rtp_protocol) {
3194
    case RTSP_PROTOCOL_RTP_UDP:
3195
    case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3196
        /* RTP/UDP case */
3197

    
3198
        /* XXX: also pass as parameter to function ? */
3199
        if (c->stream->is_multicast) {
3200
            int ttl;
3201
            ttl = c->stream->multicast_ttl;
3202
            if (!ttl)
3203
                ttl = 16;
3204
            snprintf(ctx->filename, sizeof(ctx->filename),
3205
                     "rtp://%s:%d?multicast=1&ttl=%d",
3206
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3207
        } else {
3208
            snprintf(ctx->filename, sizeof(ctx->filename),
3209
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3210
        }
3211

    
3212
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3213
            goto fail;
3214
        c->rtp_handles[stream_index] = h;
3215
        max_packet_size = url_get_max_packet_size(h);
3216
        break;
3217
    case RTSP_PROTOCOL_RTP_TCP:
3218
        /* RTP/TCP case */
3219
        c->rtsp_c = rtsp_c;
3220
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3221
        break;
3222
    default:
3223
        goto fail;
3224
    }
3225

    
3226
    http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3227
             ipaddr, ntohs(dest_addr->sin_port),
3228
             ctime1(buf2),
3229
             c->stream->filename, stream_index, c->protocol);
3230

    
3231
    /* normally, no packets should be output here, but the packet size may be checked */
3232
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3233
        /* XXX: close stream */
3234
        goto fail;
3235
    }
3236
    av_set_parameters(ctx, NULL);
3237
    if (av_write_header(ctx) < 0) {
3238
    fail:
3239
        if (h)
3240
            url_close(h);
3241
        av_free(ctx);
3242
        return -1;
3243
    }
3244
    url_close_dyn_buf(&ctx->pb, &dummy_buf);
3245
    av_free(dummy_buf);
3246

    
3247
    c->rtp_ctx[stream_index] = ctx;
3248
    return 0;
3249
}
3250

    
3251
/********************************************************************/
3252
/* ffserver initialization */
3253

    
3254
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3255
{
3256
    AVStream *fst;
3257

    
3258
    fst = av_mallocz(sizeof(AVStream));
3259
    if (!fst)
3260
        return NULL;
3261
    fst->codec= avcodec_alloc_context();
3262
    fst->priv_data = av_mallocz(sizeof(FeedData));
3263
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3264
    fst->codec->coded_frame = &dummy_frame;
3265
    fst->index = stream->nb_streams;
3266
    av_set_pts_info(fst, 33, 1, 90000);
3267
    stream->streams[stream->nb_streams++] = fst;
3268
    return fst;
3269
}
3270

    
3271
/* return the stream number in the feed */
3272
static int add_av_stream(FFStream *feed, AVStream *st)
3273
{
3274
    AVStream *fst;
3275
    AVCodecContext *av, *av1;
3276
    int i;
3277

    
3278
    av = st->codec;
3279
    for(i=0;i<feed->nb_streams;i++) {
3280
        st = feed->streams[i];
3281
        av1 = st->codec;
3282
        if (av1->codec_id == av->codec_id &&
3283
            av1->codec_type == av->codec_type &&
3284
            av1->bit_rate == av->bit_rate) {
3285

    
3286
            switch(av->codec_type) {
3287
            case CODEC_TYPE_AUDIO:
3288
                if (av1->channels == av->channels &&
3289
                    av1->sample_rate == av->sample_rate)
3290
                    goto found;
3291
                break;
3292
            case CODEC_TYPE_VIDEO:
3293
                if (av1->width == av->width &&
3294
                    av1->height == av->height &&
3295
                    av1->time_base.den == av->time_base.den &&
3296
                    av1->time_base.num == av->time_base.num &&
3297
                    av1->gop_size == av->gop_size)
3298
                    goto found;
3299
                break;
3300
            default:
3301
                av_abort();
3302
            }
3303
        }
3304
    }
3305

    
3306
    fst = add_av_stream1(feed, av);
3307
    if (!fst)
3308
        return -1;
3309
    return feed->nb_streams - 1;
3310
 found:
3311
    return i;
3312
}
3313

    
3314
static void remove_stream(FFStream *stream)
3315
{
3316
    FFStream **ps;
3317
    ps = &first_stream;
3318
    while (*ps != NULL) {
3319
        if (*ps == stream) {
3320
            *ps = (*ps)->next;
3321
        } else {
3322
            ps = &(*ps)->next;
3323
        }
3324
    }
3325
}
3326

    
3327
/* specific mpeg4 handling : we extract the raw parameters */
3328
static void extract_mpeg4_header(AVFormatContext *infile)
3329
{
3330
    int mpeg4_count, i, size;
3331
    AVPacket pkt;
3332
    AVStream *st;
3333
    const uint8_t *p;
3334

    
3335
    mpeg4_count = 0;
3336
    for(i=0;i<infile->nb_streams;i++) {
3337
        st = infile->streams[i];
3338
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3339
            st->codec->extradata_size == 0) {
3340
            mpeg4_count++;
3341
        }
3342
    }
3343
    if (!mpeg4_count)
3344
        return;
3345

    
3346
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3347
    while (mpeg4_count > 0) {
3348
        if (av_read_packet(infile, &pkt) < 0)
3349
            break;
3350
        st = infile->streams[pkt.stream_index];
3351
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3352
            st->codec->extradata_size == 0) {
3353
            av_freep(&st->codec->extradata);
3354
            /* fill extradata with the header */
3355
            /* XXX: we make hard suppositions here ! */
3356
            p = pkt.data;
3357
            while (p < pkt.data + pkt.size - 4) {
3358
                /* stop when vop header is found */
3359
                if (p[0] == 0x00 && p[1] == 0x00 &&
3360
                    p[2] == 0x01 && p[3] == 0xb6) {
3361
                    size = p - pkt.data;
3362
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3363
                    st->codec->extradata = av_malloc(size);
3364
                    st->codec->extradata_size = size;
3365
                    memcpy(st->codec->extradata, pkt.data, size);
3366
                    break;
3367
                }
3368
                p++;
3369
            }
3370
            mpeg4_count--;
3371
        }
3372
        av_free_packet(&pkt);
3373
    }
3374
}
3375

    
3376
/* compute the needed AVStream for each file */
3377
static void build_file_streams(void)
3378
{
3379
    FFStream *stream, *stream_next;
3380
    AVFormatContext *infile;
3381
    int i;
3382

    
3383
    /* gather all streams */
3384
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3385
        stream_next = stream->next;
3386
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3387
            !stream->feed) {
3388
            /* the stream comes from a file */
3389
            /* try to open the file */
3390
            /* open stream */
3391
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3392
            if (stream->fmt == &rtp_muxer) {
3393
                /* specific case : if transport stream output to RTP,
3394
                   we use a raw transport stream reader */
3395
                stream->ap_in->mpeg2ts_raw = 1;
3396
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3397
            }
3398

    
3399
            if (av_open_input_file(&infile, stream->feed_filename,
3400
                                   stream->ifmt, 0, stream->ap_in) < 0) {
3401
                http_log("%s not found", stream->feed_filename);
3402
                /* remove stream (no need to spend more time on it) */
3403
            fail:
3404
                remove_stream(stream);
3405
            } else {
3406
                /* find all the AVStreams inside and reference them in
3407
                   'stream' */
3408
                if (av_find_stream_info(infile) < 0) {
3409
                    http_log("Could not find codec parameters from '%s'",
3410
                             stream->feed_filename);
3411
                    av_close_input_file(infile);
3412
                    goto fail;
3413
                }
3414
                extract_mpeg4_header(infile);
3415

    
3416
                for(i=0;i<infile->nb_streams;i++) {
3417
                    add_av_stream1(stream, infile->streams[i]->codec);
3418
                }
3419
                av_close_input_file(infile);
3420
            }
3421
        }
3422
    }
3423
}
3424

    
3425
/* compute the needed AVStream for each feed */
3426
static void build_feed_streams(void)
3427
{
3428
    FFStream *stream, *feed;
3429
    int i;
3430

    
3431
    /* gather all streams */
3432
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3433
        feed = stream->feed;
3434
        if (feed) {
3435
            if (!stream->is_feed) {
3436
                /* we handle a stream coming from a feed */
3437
                for(i=0;i<stream->nb_streams;i++) {
3438
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3439
                }
3440
            }
3441
        }
3442
    }
3443

    
3444
    /* gather all streams */
3445
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3446
        feed = stream->feed;
3447
        if (feed) {
3448
            if (stream->is_feed) {
3449
                for(i=0;i<stream->nb_streams;i++) {
3450
                    stream->feed_streams[i] = i;
3451
                }
3452
            }
3453
        }
3454
    }
3455

    
3456
    /* create feed files if needed */
3457
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3458
        int fd;
3459

    
3460
        if (url_exist(feed->feed_filename)) {
3461
            /* See if it matches */
3462
            AVFormatContext *s;
3463
            int matches = 0;
3464

    
3465
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3466
                /* Now see if it matches */
3467
                if (s->nb_streams == feed->nb_streams) {
3468
                    matches = 1;
3469
                    for(i=0;i<s->nb_streams;i++) {
3470
                        AVStream *sf, *ss;
3471
                        sf = feed->streams[i];
3472
                        ss = s->streams[i];
3473

    
3474
                        if (sf->index != ss->index ||
3475
                            sf->id != ss->id) {
3476
                            printf("Index & Id do not match for stream %d (%s)\n",
3477
                                   i, feed->feed_filename);
3478
                            matches = 0;
3479
                        } else {
3480
                            AVCodecContext *ccf, *ccs;
3481

    
3482
                            ccf = sf->codec;
3483
                            ccs = ss->codec;
3484
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3485

    
3486
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3487
                                printf("Codecs do not match for stream %d\n", i);
3488
                                matches = 0;
3489
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3490
                                printf("Codec bitrates do not match for stream %d\n", i);
3491
                                matches = 0;
3492
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3493
                                if (CHECK_CODEC(time_base.den) ||
3494
                                    CHECK_CODEC(time_base.num) ||
3495
                                    CHECK_CODEC(width) ||
3496
                                    CHECK_CODEC(height)) {
3497
                                    printf("Codec width, height and framerate do not match for stream %d\n", i);
3498
                                    matches = 0;
3499
                                }
3500
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3501
                                if (CHECK_CODEC(sample_rate) ||
3502
                                    CHECK_CODEC(channels) ||
3503
                                    CHECK_CODEC(frame_size)) {
3504
                                    printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3505
                                    matches = 0;
3506
                                }
3507
                            } else {
3508
                                printf("Unknown codec type\n");
3509
                                matches = 0;
3510
                            }
3511
                        }
3512
                        if (!matches) {
3513
                            break;
3514
                        }
3515
                    }
3516
                } else {
3517
                    printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3518
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3519
                }
3520

    
3521
                av_close_input_file(s);
3522
            } else {
3523
                printf("Deleting feed file '%s' as it appears to be corrupt\n",
3524
                        feed->feed_filename);
3525
            }
3526
            if (!matches) {
3527
                if (feed->readonly) {
3528
                    printf("Unable to delete feed file '%s' as it is marked readonly\n",
3529
                        feed->feed_filename);
3530
                    exit(1);
3531
                }
3532
                unlink(feed->feed_filename);
3533
            }
3534
        }
3535
        if (!url_exist(feed->feed_filename)) {
3536
            AVFormatContext s1, *s = &s1;
3537

    
3538
            if (feed->readonly) {
3539
                printf("Unable to create feed file '%s' as it is marked readonly\n",
3540
                    feed->feed_filename);
3541
                exit(1);
3542
            }
3543

    
3544
            /* only write the header of the ffm file */
3545
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3546
                fprintf(stderr, "Could not open output feed file '%s'\n",
3547
                        feed->feed_filename);
3548
                exit(1);
3549
            }
3550
            s->oformat = feed->fmt;
3551
            s->nb_streams = feed->nb_streams;
3552
            for(i=0;i<s->nb_streams;i++) {
3553
                AVStream *st;
3554
                st = feed->streams[i];
3555
                s->streams[i] = st;
3556
            }
3557
            av_set_parameters(s, NULL);
3558
            if (av_write_header(s) < 0) {
3559
                fprintf(stderr, "Container doesn't supports the required parameters\n");
3560
                exit(1);
3561
            }
3562
            /* XXX: need better api */
3563
            av_freep(&s->priv_data);
3564
            url_fclose(&s->pb);
3565
        }
3566
        /* get feed size and write index */
3567
        fd = open(feed->feed_filename, O_RDONLY);
3568
        if (fd < 0) {
3569
            fprintf(stderr, "Could not open output feed file '%s'\n",
3570
                    feed->feed_filename);
3571
            exit(1);
3572
        }
3573

    
3574
        feed->feed_write_index = ffm_read_write_index(fd);
3575
        feed->feed_size = lseek(fd, 0, SEEK_END);
3576
        /* ensure that we do not wrap before the end of file */
3577
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3578
            feed->feed_max_size = feed->feed_size;
3579

    
3580
        close(fd);
3581
    }
3582
}
3583

    
3584
/* compute the bandwidth used by each stream */
3585
static void compute_bandwidth(void)
3586
{
3587
    int bandwidth, i;
3588
    FFStream *stream;
3589

    
3590
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3591
        bandwidth = 0;
3592
        for(i=0;i<stream->nb_streams;i++) {
3593
            AVStream *st = stream->streams[i];
3594
            switch(st->codec->codec_type) {
3595
            case CODEC_TYPE_AUDIO:
3596
            case CODEC_TYPE_VIDEO:
3597
                bandwidth += st->codec->bit_rate;
3598
                break;
3599
            default:
3600
                break;
3601
            }
3602
        }
3603
        stream->bandwidth = (bandwidth + 999) / 1000;
3604
    }
3605
}
3606

    
3607
static void get_arg(char *buf, int buf_size, const char **pp)
3608
{
3609
    const char *p;
3610
    char *q;
3611
    int quote;
3612

    
3613
    p = *pp;
3614
    while (isspace(*p)) p++;
3615
    q = buf;
3616
    quote = 0;
3617
    if (*p == '\"' || *p == '\'')
3618
        quote = *p++;
3619
    for(;;) {
3620
        if (quote) {
3621
            if (*p == quote)
3622
                break;
3623
        } else {
3624
            if (isspace(*p))
3625
                break;
3626
        }
3627
        if (*p == '\0')
3628
            break;
3629
        if ((q - buf) < buf_size - 1)
3630
            *q++ = *p;
3631
        p++;
3632
    }
3633
    *q = '\0';
3634
    if (quote && *p == quote)
3635
        p++;
3636
    *pp = p;
3637
}
3638

    
3639
/* add a codec and set the default parameters */
3640
static void add_codec(FFStream *stream, AVCodecContext *av)
3641
{
3642
    AVStream *st;
3643

    
3644
    /* compute default parameters */
3645
    switch(av->codec_type) {
3646
    case CODEC_TYPE_AUDIO:
3647
        if (av->bit_rate == 0)
3648
            av->bit_rate = 64000;
3649
        if (av->sample_rate == 0)
3650
            av->sample_rate = 22050;
3651
        if (av->channels == 0)
3652
            av->channels = 1;
3653
        break;
3654
    case CODEC_TYPE_VIDEO:
3655
        if (av->bit_rate == 0)
3656
            av->bit_rate = 64000;
3657
        if (av->time_base.num == 0){
3658
            av->time_base.den = 5;
3659
            av->time_base.num = 1;
3660
        }
3661
        if (av->width == 0 || av->height == 0) {
3662
            av->width = 160;
3663
            av->height = 128;
3664
        }
3665
        /* Bitrate tolerance is less for streaming */
3666
        if (av->bit_rate_tolerance == 0)
3667
            av->bit_rate_tolerance = av->bit_rate / 4;
3668
        if (av->qmin == 0)
3669
            av->qmin = 3;
3670
        if (av->qmax == 0)
3671
            av->qmax = 31;
3672
        if (av->max_qdiff == 0)
3673
            av->max_qdiff = 3;
3674
        av->qcompress = 0.5;
3675
        av->qblur = 0.5;
3676

    
3677
        if (!av->nsse_weight)
3678
            av->nsse_weight = 8;
3679

    
3680
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3681
        av->me_method = ME_EPZS;
3682
        av->rc_buffer_aggressivity = 1.0;
3683

    
3684
        if (!av->rc_eq)
3685
            av->rc_eq = "tex^qComp";
3686
        if (!av->i_quant_factor)
3687
            av->i_quant_factor = -0.8;
3688
        if (!av->b_quant_factor)
3689
            av->b_quant_factor = 1.25;
3690
        if (!av->b_quant_offset)
3691
            av->b_quant_offset = 1.25;
3692
        if (!av->rc_max_rate)
3693
            av->rc_max_rate = av->bit_rate * 2;
3694

    
3695
        if (av->rc_max_rate && !av->rc_buffer_size) {
3696
            av->rc_buffer_size = av->rc_max_rate;
3697
        }
3698

    
3699

    
3700
        break;
3701
    default:
3702
        av_abort();
3703
    }
3704

    
3705
    st = av_mallocz(sizeof(AVStream));
3706
    if (!st)
3707
        return;
3708
    st->codec = avcodec_alloc_context();
3709
    stream->streams[stream->nb_streams++] = st;
3710
    memcpy(st->codec, av, sizeof(AVCodecContext));
3711
}
3712

    
3713
static int opt_audio_codec(const char *arg)
3714
{
3715
    AVCodec *p;
3716

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

    
3727
    return p->id;
3728
}
3729

    
3730
static int opt_video_codec(const char *arg)
3731
{
3732
    AVCodec *p;
3733

    
3734
    p = first_avcodec;
3735
    while (p) {
3736
        if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3737
            break;
3738
        p = p->next;
3739
    }
3740
    if (p == NULL) {
3741
        return CODEC_ID_NONE;
3742
    }
3743

    
3744
    return p->id;
3745
}
3746

    
3747
/* simplistic plugin support */
3748

    
3749
#ifdef HAVE_DLOPEN
3750
static void load_module(const char *filename)
3751
{
3752
    void *dll;
3753
    void (*init_func)(void);
3754
    dll = dlopen(filename, RTLD_NOW);
3755
    if (!dll) {
3756
        fprintf(stderr, "Could not load module '%s' - %s\n",
3757
                filename, dlerror());
3758
        return;
3759
    }
3760

    
3761
    init_func = dlsym(dll, "ffserver_module_init");
3762
    if (!init_func) {
3763
        fprintf(stderr,
3764
                "%s: init function 'ffserver_module_init()' not found\n",
3765
                filename);
3766
        dlclose(dll);
3767
    }
3768

    
3769
    init_func();
3770
}
3771
#endif
3772

    
3773
static int parse_ffconfig(const char *filename)
3774
{
3775
    FILE *f;
3776
    char line[1024];
3777
    char cmd[64];
3778
    char arg[1024];
3779
    const char *p;
3780
    int val, errors, line_num;
3781
    FFStream **last_stream, *stream, *redirect;
3782
    FFStream **last_feed, *feed;
3783
    AVCodecContext audio_enc, video_enc;
3784
    int audio_id, video_id;
3785

    
3786
    f = fopen(filename, "r");
3787
    if (!f) {
3788
        perror(filename);
3789
        return -1;
3790
    }
3791

    
3792
    errors = 0;
3793
    line_num = 0;
3794
    first_stream = NULL;
3795
    last_stream = &first_stream;
3796
    first_feed = NULL;
3797
    last_feed = &first_feed;
3798
    stream = NULL;
3799
    feed = NULL;
3800
    redirect = NULL;
3801
    audio_id = CODEC_ID_NONE;
3802
    video_id = CODEC_ID_NONE;
3803
    for(;;) {
3804
        if (fgets(line, sizeof(line), f) == NULL)
3805
            break;
3806
        line_num++;
3807
        p = line;
3808
        while (isspace(*p))
3809
            p++;
3810
        if (*p == '\0' || *p == '#')
3811
            continue;
3812

    
3813
        get_arg(cmd, sizeof(cmd), &p);
3814

    
3815
        if (!strcasecmp(cmd, "Port")) {
3816
            get_arg(arg, sizeof(arg), &p);
3817
            val = atoi(arg);
3818
            if (val < 1 || val > 65536) {
3819
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3820
                        filename, line_num, arg);
3821
                errors++;
3822
            }
3823
            my_http_addr.sin_port = htons(val);
3824
        } else if (!strcasecmp(cmd, "BindAddress")) {
3825
            get_arg(arg, sizeof(arg), &p);
3826
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3827
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3828
                        filename, line_num, arg);
3829
                errors++;
3830
            }
3831
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3832
            ffserver_daemon = 0;
3833
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3834
            get_arg(arg, sizeof(arg), &p);
3835
            val = atoi(arg);
3836
            if (val < 1 || val > 65536) {
3837
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3838
                        filename, line_num, arg);
3839
                errors++;
3840
            }
3841
            my_rtsp_addr.sin_port = htons(atoi(arg));
3842
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3843
            get_arg(arg, sizeof(arg), &p);
3844
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3845
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3846
                        filename, line_num, arg);
3847
                errors++;
3848
            }
3849
        } else if (!strcasecmp(cmd, "MaxClients")) {
3850
            get_arg(arg, sizeof(arg), &p);
3851
            val = atoi(arg);
3852
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3853
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3854
                        filename, line_num, arg);
3855
                errors++;
3856
            } else {
3857
                nb_max_connections = val;
3858
            }
3859
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3860
            get_arg(arg, sizeof(arg), &p);
3861
            val = atoi(arg);
3862
            if (val < 10 || val > 100000) {
3863
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3864
                        filename, line_num, arg);
3865
                errors++;
3866
            } else {
3867
                max_bandwidth = val;
3868
            }
3869
        } else if (!strcasecmp(cmd, "CustomLog")) {
3870
            get_arg(logfilename, sizeof(logfilename), &p);
3871
        } else if (!strcasecmp(cmd, "<Feed")) {
3872
            /*********************************************/
3873
            /* Feed related options */
3874
            char *q;
3875
            if (stream || feed) {
3876
                fprintf(stderr, "%s:%d: Already in a tag\n",
3877
                        filename, line_num);
3878
            } else {
3879
                feed = av_mallocz(sizeof(FFStream));
3880
                /* add in stream list */
3881
                *last_stream = feed;
3882
                last_stream = &feed->next;
3883
                /* add in feed list */
3884
                *last_feed = feed;
3885
                last_feed = &feed->next_feed;
3886

    
3887
                get_arg(feed->filename, sizeof(feed->filename), &p);
3888
                q = strrchr(feed->filename, '>');
3889
                if (*q)
3890
                    *q = '\0';
3891
                feed->fmt = guess_format("ffm", NULL, NULL);
3892
                /* defaut feed file */
3893
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3894
                         "/tmp/%s.ffm", feed->filename);
3895
                feed->feed_max_size = 5 * 1024 * 1024;
3896
                feed->is_feed = 1;
3897
                feed->feed = feed; /* self feeding :-) */
3898
            }
3899
        } else if (!strcasecmp(cmd, "Launch")) {
3900
            if (feed) {
3901
                int i;
3902

    
3903
                feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3904

    
3905
                for (i = 0; i < 62; i++) {
3906
                    get_arg(arg, sizeof(arg), &p);
3907
                    if (!arg[0])
3908
                        break;
3909

    
3910
                    feed->child_argv[i] = av_strdup(arg);
3911
                }
3912

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

    
3915
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3916
                    "http://%s:%d/%s",
3917
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3918
                    inet_ntoa(my_http_addr.sin_addr),
3919
                    ntohs(my_http_addr.sin_port), feed->filename);
3920

    
3921
                if (ffserver_debug)
3922
                {
3923
                    int j;
3924
                    fprintf(stdout, "Launch commandline: ");
3925
                    for (j = 0; j <= i; j++)
3926
                        fprintf(stdout, "%s ", feed->child_argv[j]);
3927
                    fprintf(stdout, "\n");
3928
                }
3929
            }
3930
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3931
            if (feed) {
3932
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3933
                feed->readonly = 1;
3934
            } else if (stream) {
3935
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3936
            }
3937
        } else if (!strcasecmp(cmd, "File")) {
3938
            if (feed) {
3939
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3940
            } else if (stream) {
3941
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3942
            }
3943
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3944
            if (feed) {
3945
                const char *p1;
3946
                double fsize;
3947

    
3948
                get_arg(arg, sizeof(arg), &p);
3949
                p1 = arg;
3950
                fsize = strtod(p1, (char **)&p1);
3951
                switch(toupper(*p1)) {
3952
                case 'K':
3953
                    fsize *= 1024;
3954
                    break;
3955
                case 'M':
3956
                    fsize *= 1024 * 1024;
3957
                    break;
3958
                case 'G':
3959
                    fsize *= 1024 * 1024 * 1024;
3960
                    break;
3961
                }
3962
                feed->feed_max_size = (int64_t)fsize;
3963
            }
3964
        } else if (!strcasecmp(cmd, "</Feed>")) {
3965
            if (!feed) {
3966
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3967
                        filename, line_num);
3968
                errors++;
3969
            }
3970
            feed = NULL;
3971
        } else if (!strcasecmp(cmd, "<Stream")) {
3972
            /*********************************************/
3973
            /* Stream related options */
3974
            char *q;
3975
            if (stream || feed) {
3976
                fprintf(stderr, "%s:%d: Already in a tag\n",
3977
                        filename, line_num);
3978
            } else {
3979
                stream = av_mallocz(sizeof(FFStream));
3980
                *last_stream = stream;
3981
                last_stream = &stream->next;
3982

    
3983
                get_arg(stream->filename, sizeof(stream->filename), &p);
3984
                q = strrchr(stream->filename, '>');
3985
                if (*q)
3986
                    *q = '\0';
3987
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3988
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3989
                memset(&video_enc, 0, sizeof(AVCodecContext));
3990
                audio_id = CODEC_ID_NONE;
3991
                video_id = CODEC_ID_NONE;
3992
                if (stream->fmt) {
3993
                    audio_id = stream->fmt->audio_codec;
3994
                    video_id = stream->fmt->video_codec;
3995
                }
3996
            }
3997
        } else if (!strcasecmp(cmd, "Feed")) {
3998
            get_arg(arg, sizeof(arg), &p);
3999
            if (stream) {
4000
                FFStream *sfeed;
4001

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

    
4121
                get_arg(arg, sizeof(arg), &p);
4122

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

    
4272
            get_arg(arg, sizeof(arg), &p);
4273
            if (strcasecmp(arg, "allow") == 0) {
4274
                acl.action = IP_ALLOW;
4275
            } else if (strcasecmp(arg, "deny") == 0) {
4276
                acl.action = IP_DENY;
4277
            } else {
4278
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4279
                        filename, line_num, arg);
4280
                errors++;
4281
            }
4282

    
4283
            get_arg(arg, sizeof(arg), &p);
4284
            
4285
            if (resolve_host(&acl.first, arg) != 0) {
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
                acl.last = acl.first;
4291
            }
4292

    
4293
            get_arg(arg, sizeof(arg), &p);
4294

    
4295
            if (arg[0]) {
4296
                if (resolve_host(&acl.last, arg) != 0) {
4297
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4298
                            filename, line_num, arg);
4299
                    errors++;
4300
                }
4301
            }
4302

    
4303
            if (!errors) {
4304
                IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4305
                IPAddressACL **naclp = 0;
4306

    
4307
                acl.next = 0;
4308
                *nacl = acl;
4309

    
4310
                if (stream) {
4311
                    naclp = &stream->acl;
4312
                } else if (feed) {
4313
                    naclp = &feed->acl;
4314
                } else {
4315
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4316
                            filename, line_num);
4317
                    errors++;
4318
                }
4319

    
4320
                if (naclp) {
4321
                    while (*naclp)
4322
                        naclp = &(*naclp)->next;
4323

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

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

    
4427
    fclose(f);
4428
    if (errors)
4429
        return -1;
4430
    else
4431
        return 0;
4432
}
4433

    
4434
static void show_banner(void)
4435
{
4436
    printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
4437
}
4438

    
4439
static void show_help(void)
4440
{
4441
    show_banner();
4442
    printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4443
           "Hyper fast multi format Audio/Video streaming server\n"
4444
           "\n"
4445
           "-L            : print the LICENSE\n"
4446
           "-h            : this help\n"
4447
           "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4448
           );
4449
}
4450

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

    
4471
static void handle_child_exit(int sig)
4472
{
4473
    pid_t pid;
4474
    int status;
4475

    
4476
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4477
        FFStream *feed;
4478

    
4479
        for (feed = first_feed; feed; feed = feed->next) {
4480
            if (feed->pid == pid) {
4481
                int uptime = time(0) - feed->pid_start;
4482

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

    
4486
                if (uptime < 30) {
4487
                    /* Turn off any more restarts */
4488
                    feed->child_argv = 0;
4489
                }
4490
            }
4491
        }
4492
    }
4493

    
4494
    need_to_start_children = 1;
4495
}
4496

    
4497
int main(int argc, char **argv)
4498
{
4499
    const char *config_filename;
4500
    int c;
4501
    struct sigaction sigact;
4502

    
4503
    av_register_all();
4504

    
4505
    config_filename = "/etc/ffserver.conf";
4506

    
4507
    my_program_name = argv[0];
4508
    my_program_dir = getcwd(0, 0);
4509
    ffserver_daemon = 1;
4510

    
4511
    for(;;) {
4512
        c = getopt(argc, argv, "ndLh?f:");
4513
        if (c == -1)
4514
            break;
4515
        switch(c) {
4516
        case 'L':
4517
            show_license();
4518
            exit(1);
4519
        case '?':
4520
        case 'h':
4521
            show_help();
4522
            exit(1);
4523
        case 'n':
4524
            no_launch = 1;
4525
            break;
4526
        case 'd':
4527
            ffserver_debug = 1;
4528
            ffserver_daemon = 0;
4529
            break;
4530
        case 'f':
4531
            config_filename = optarg;
4532
            break;
4533
        default:
4534
            exit(2);
4535
        }
4536
    }
4537

    
4538
    putenv("http_proxy");               /* Kill the http_proxy */
4539

    
4540
    av_init_random(av_gettime() + (getpid() << 16), &random_state);
4541

    
4542
    /* address on which the server will handle HTTP connections */
4543
    my_http_addr.sin_family = AF_INET;
4544
    my_http_addr.sin_port = htons (8080);
4545
    my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4546

    
4547
    /* address on which the server will handle RTSP connections */
4548
    my_rtsp_addr.sin_family = AF_INET;
4549
    my_rtsp_addr.sin_port = htons (5454);
4550
    my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4551

    
4552
    nb_max_connections = 5;
4553
    max_bandwidth = 1000;
4554
    first_stream = NULL;
4555
    logfilename[0] = '\0';
4556

    
4557
    memset(&sigact, 0, sizeof(sigact));
4558
    sigact.sa_handler = handle_child_exit;
4559
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4560
    sigaction(SIGCHLD, &sigact, 0);
4561

    
4562
    if (parse_ffconfig(config_filename) < 0) {
4563
        fprintf(stderr, "Incorrect config file - exiting.\n");
4564
        exit(1);
4565
    }
4566

    
4567
    build_file_streams();
4568

    
4569
    build_feed_streams();
4570

    
4571
    compute_bandwidth();
4572

    
4573
    /* put the process in background and detach it from its TTY */
4574
    if (ffserver_daemon) {
4575
        int pid;
4576

    
4577
        pid = fork();
4578
        if (pid < 0) {
4579
            perror("fork");
4580
            exit(1);
4581
        } else if (pid > 0) {
4582
            /* parent : exit */
4583
            exit(0);
4584
        } else {
4585
            /* child */
4586
            setsid();
4587
            chdir("/");
4588
            close(0);
4589
            open("/dev/null", O_RDWR);
4590
            if (strcmp(logfilename, "-") != 0) {
4591
                close(1);
4592
                dup(0);
4593
            }
4594
            close(2);
4595
            dup(0);
4596
        }
4597
    }
4598

    
4599
    /* signal init */
4600
    signal(SIGPIPE, SIG_IGN);
4601

    
4602
    /* open log file if needed */
4603
    if (logfilename[0] != '\0') {
4604
        if (!strcmp(logfilename, "-"))
4605
            logfile = stdout;
4606
        else
4607
            logfile = fopen(logfilename, "w");
4608
    }
4609

    
4610
    if (http_server() < 0) {
4611
        fprintf(stderr, "Could not start server\n");
4612
        exit(1);
4613
    }
4614

    
4615
    return 0;
4616
}