~ubuntu-branches/ubuntu/maverick/ffmpeg/maverick-security

1 by Daniel T Chen
Import upstream version 0.cvs20050918
1
/*
2
 * Multiple format streaming server
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
1 by Daniel T Chen
Import upstream version 0.cvs20050918
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
10
 * version 2.1 of the License, or (at your option) any later version.
1 by Daniel T Chen
Import upstream version 0.cvs20050918
11
 *
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
12
 * FFmpeg is distributed in the hope that it will be useful,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
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
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
18
 * License along with FFmpeg; if not, write to the Free Software
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1 by Daniel T Chen
Import upstream version 0.cvs20050918
20
 */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
21
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
22
#define _XOPEN_SOURCE 600
23
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
24
#include "config.h"
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
25
#if !HAVE_CLOSESOCKET
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
26
#define closesocket close
27
#endif
28
#include <string.h>
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
29
#include <strings.h>
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
30
#include <stdlib.h>
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
31
#include "libavformat/avformat.h"
32
#include "libavformat/network.h"
33
#include "libavformat/os_support.h"
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
34
#include "libavformat/rtpdec.h"
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
35
#include "libavformat/rtsp.h"
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
36
#include "libavutil/avstring.h"
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
37
#include "libavutil/lfg.h"
38
#include "libavutil/random_seed.h"
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
39
#include "libavcodec/opt.h"
1 by Daniel T Chen
Import upstream version 0.cvs20050918
40
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
44
#if HAVE_POLL_H
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
45
#include <poll.h>
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
46
#endif
1 by Daniel T Chen
Import upstream version 0.cvs20050918
47
#include <errno.h>
48
#include <sys/time.h>
49
#include <time.h>
50
#include <sys/wait.h>
51
#include <signal.h>
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
52
#if HAVE_DLFCN_H
1 by Daniel T Chen
Import upstream version 0.cvs20050918
53
#include <dlfcn.h>
54
#endif
55
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
56
#include "cmdutils.h"
57
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
58
const char program_name[] = "FFserver";
59
const int program_birth_year = 2000;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
60
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
61
static const OptionDef options[];
1 by Daniel T Chen
Import upstream version 0.cvs20050918
62
63
enum HTTPState {
64
    HTTPSTATE_WAIT_REQUEST,
65
    HTTPSTATE_SEND_HEADER,
66
    HTTPSTATE_SEND_DATA_HEADER,
67
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
68
    HTTPSTATE_SEND_DATA_TRAILER,
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
69
    HTTPSTATE_RECEIVE_DATA,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
70
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
71
    HTTPSTATE_READY,
72
73
    RTSPSTATE_WAIT_REQUEST,
74
    RTSPSTATE_SEND_REPLY,
75
    RTSPSTATE_SEND_PACKET,
76
};
77
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
78
static const char *http_state[] = {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
79
    "HTTP_WAIT_REQUEST",
80
    "HTTP_SEND_HEADER",
81
82
    "SEND_DATA_HEADER",
83
    "SEND_DATA",
84
    "SEND_DATA_TRAILER",
85
    "RECEIVE_DATA",
86
    "WAIT_FEED",
87
    "READY",
88
89
    "RTSP_WAIT_REQUEST",
90
    "RTSP_SEND_REPLY",
91
    "RTSP_SEND_PACKET",
92
};
93
94
#define IOBUFFER_INIT_SIZE 8192
95
96
/* timeouts are in ms */
97
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
98
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
99
100
#define SYNC_TIMEOUT (10 * 1000)
101
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
102
typedef struct RTSPActionServerSetup {
103
    uint32_t ipaddr;
104
    char transport_option[512];
105
} RTSPActionServerSetup;
106
1 by Daniel T Chen
Import upstream version 0.cvs20050918
107
typedef struct {
108
    int64_t count1, count2;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
109
    int64_t time1, time2;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
110
} DataRateData;
111
112
/* context associated with one connection */
113
typedef struct HTTPContext {
114
    enum HTTPState state;
115
    int fd; /* socket file descriptor */
116
    struct sockaddr_in from_addr; /* origin */
117
    struct pollfd *poll_entry; /* used when polling */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
118
    int64_t timeout;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
119
    uint8_t *buffer_ptr, *buffer_end;
120
    int http_error;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
121
    int post;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
122
    int chunked_encoding;
123
    int chunk_size;               /* 0 if it needs to be read */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
124
    struct HTTPContext *next;
125
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
126
    int64_t data_count;
127
    /* feed input */
128
    int feed_fd;
129
    /* input format handling */
130
    AVFormatContext *fmt_in;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
131
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
132
    int64_t first_pts;            /* initial pts value */
133
    int64_t cur_pts;             /* current pts value from the stream in us */
134
    int64_t cur_frame_duration;  /* duration of the current frame in us */
135
    int cur_frame_bytes;       /* output frame size, needed to compute
136
                                  the time at which we send each
137
                                  packet */
138
    int pts_stream_index;        /* stream we choose as clock reference */
139
    int64_t cur_clock;           /* current clock reference value in us */
140
    /* output format handling */
141
    struct FFStream *stream;
142
    /* -1 is invalid stream */
143
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
144
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
145
    int switch_pending;
146
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
147
    int last_packet_sent; /* true if last data packet was sent */
148
    int suppress_log;
149
    DataRateData datarate;
150
    int wmp_client_id;
151
    char protocol[16];
152
    char method[16];
153
    char url[128];
154
    int buffer_size;
155
    uint8_t *buffer;
156
    int is_packetized; /* if true, the stream is packetized */
157
    int packet_stream_index; /* current stream for output in state machine */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
158
1 by Daniel T Chen
Import upstream version 0.cvs20050918
159
    /* RTSP state specific */
160
    uint8_t *pb_buffer; /* XXX: use that in all the code */
161
    ByteIOContext *pb;
162
    int seq; /* RTSP sequence number */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
163
1 by Daniel T Chen
Import upstream version 0.cvs20050918
164
    /* RTP state specific */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
165
    enum RTSPLowerTransport rtp_protocol;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
166
    char session_id[32]; /* session id */
167
    AVFormatContext *rtp_ctx[MAX_STREAMS];
168
169
    /* RTP/UDP specific */
170
    URLContext *rtp_handles[MAX_STREAMS];
171
172
    /* RTP/TCP specific */
173
    struct HTTPContext *rtsp_c;
174
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
175
} HTTPContext;
176
177
/* each generated stream is described here */
178
enum StreamType {
179
    STREAM_TYPE_LIVE,
180
    STREAM_TYPE_STATUS,
181
    STREAM_TYPE_REDIRECT,
182
};
183
184
enum IPAddressAction {
185
    IP_ALLOW = 1,
186
    IP_DENY,
187
};
188
189
typedef struct IPAddressACL {
190
    struct IPAddressACL *next;
191
    enum IPAddressAction action;
192
    /* These are in host order */
193
    struct in_addr first;
194
    struct in_addr last;
195
} IPAddressACL;
196
197
/* description of each stream of the ffserver.conf file */
198
typedef struct FFStream {
199
    enum StreamType stream_type;
200
    char filename[1024];     /* stream filename */
201
    struct FFStream *feed;   /* feed we are using (can be null if
202
                                coming from file) */
203
    AVFormatParameters *ap_in; /* input parameters */
204
    AVInputFormat *ifmt;       /* if non NULL, force input format */
205
    AVOutputFormat *fmt;
206
    IPAddressACL *acl;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
207
    char dynamic_acl[1024];
1 by Daniel T Chen
Import upstream version 0.cvs20050918
208
    int nb_streams;
209
    int prebuffer;      /* Number of millseconds early to start */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
210
    int64_t max_time;      /* Number of milliseconds to run */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
211
    int send_on_key;
212
    AVStream *streams[MAX_STREAMS];
213
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
214
    char feed_filename[1024]; /* file name of the feed storage, or
215
                                 input file name for a stream */
216
    char author[512];
217
    char title[512];
218
    char copyright[512];
219
    char comment[512];
220
    pid_t pid;  /* Of ffmpeg process */
221
    time_t pid_start;  /* Of ffmpeg process */
222
    char **child_argv;
223
    struct FFStream *next;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
224
    unsigned bandwidth; /* bandwidth, in kbits/s */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
225
    /* RTSP options */
226
    char *rtsp_option;
227
    /* multicast specific */
228
    int is_multicast;
229
    struct in_addr multicast_ip;
230
    int multicast_port; /* first port used for multicast */
231
    int multicast_ttl;
232
    int loop; /* if true, send the stream in loops (only meaningful if file) */
233
234
    /* feed specific */
235
    int feed_opened;     /* true if someone is writing to the feed */
236
    int is_feed;         /* true if it is a feed */
237
    int readonly;        /* True if writing is prohibited to the file */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
238
    int truncate;        /* True if feeder connection truncate the feed file */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
239
    int conns_served;
240
    int64_t bytes_served;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
241
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
242
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
243
    int64_t feed_size;          /* current size of feed */
244
    struct FFStream *next_feed;
245
} FFStream;
246
247
typedef struct FeedData {
248
    long long data_count;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
249
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
250
} FeedData;
251
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
252
static struct sockaddr_in my_http_addr;
253
static struct sockaddr_in my_rtsp_addr;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
254
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
255
static char logfilename[1024];
256
static HTTPContext *first_http_ctx;
257
static FFStream *first_feed;   /* contains only feeds */
258
static FFStream *first_stream; /* contains all streams, including feeds */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
259
260
static void new_connection(int server_fd, int is_rtsp);
261
static void close_connection(HTTPContext *c);
262
263
/* HTTP handling */
264
static int handle_connection(HTTPContext *c);
265
static int http_parse_request(HTTPContext *c);
266
static int http_send_data(HTTPContext *c);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
267
static void compute_status(HTTPContext *c);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
268
static int open_input_stream(HTTPContext *c, const char *info);
269
static int http_start_receive_data(HTTPContext *c);
270
static int http_receive_data(HTTPContext *c);
271
272
/* RTSP handling */
273
static int rtsp_parse_request(HTTPContext *c);
274
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
275
static void rtsp_cmd_options(HTTPContext *c, const char *url);
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
276
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
277
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
278
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
279
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
280
281
/* SDP handling */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
282
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
283
                                   struct in_addr my_ip);
284
285
/* RTP handling */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
286
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
287
                                       FFStream *stream, const char *session_id,
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
288
                                       enum RTSPLowerTransport rtp_protocol);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
289
static int rtp_new_av_stream(HTTPContext *c,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
290
                             int stream_index, struct sockaddr_in *dest_addr,
291
                             HTTPContext *rtsp_c);
292
293
static const char *my_program_name;
294
static const char *my_program_dir;
295
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
296
static const char *config_filename = "/etc/ffserver.conf";
297
1 by Daniel T Chen
Import upstream version 0.cvs20050918
298
static int ffserver_debug;
299
static int ffserver_daemon;
300
static int no_launch;
301
static int need_to_start_children;
302
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
303
/* maximum number of simultaneous HTTP connections */
304
static unsigned int nb_max_http_connections = 2000;
305
static unsigned int nb_max_connections = 5;
306
static unsigned int nb_connections;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
307
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
308
static uint64_t max_bandwidth = 1000;
309
static uint64_t current_bandwidth;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
310
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
311
static int64_t cur_time;           // Making this global saves on passing it around everywhere
312
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
313
static AVLFG random_state;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
314
315
static FILE *logfile = NULL;
316
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
317
/* FIXME: make ffserver work with IPv6 */
318
/* resolve host with also IP address parsing */
319
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
320
{
321
322
    if (!ff_inet_aton(hostname, sin_addr)) {
323
#if HAVE_GETADDRINFO
324
        struct addrinfo *ai, *cur;
325
        struct addrinfo hints;
326
        memset(&hints, 0, sizeof(hints));
327
        hints.ai_family = AF_INET;
328
        if (getaddrinfo(hostname, NULL, &hints, &ai))
329
            return -1;
330
        /* getaddrinfo returns a linked list of addrinfo structs.
331
         * Even if we set ai_family = AF_INET above, make sure
332
         * that the returned one actually is of the correct type. */
333
        for (cur = ai; cur; cur = cur->ai_next) {
334
            if (cur->ai_family == AF_INET) {
335
                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
336
                freeaddrinfo(ai);
337
                return 0;
338
            }
339
        }
340
        freeaddrinfo(ai);
341
        return -1;
342
#else
343
        struct hostent *hp;
344
        hp = gethostbyname(hostname);
345
        if (!hp)
346
            return -1;
347
        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
348
#endif
349
    }
350
    return 0;
351
}
352
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
353
static char *ctime1(char *buf2)
354
{
355
    time_t ti;
356
    char *p;
357
358
    ti = time(NULL);
359
    p = ctime(&ti);
360
    strcpy(buf2, p);
361
    p = buf2 + strlen(p) - 1;
362
    if (*p == '\n')
363
        *p = '\0';
364
    return buf2;
365
}
366
367
static void http_vlog(const char *fmt, va_list vargs)
368
{
369
    static int print_prefix = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
370
    if (logfile) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
371
        if (print_prefix) {
372
            char buf[32];
373
            ctime1(buf);
374
            fprintf(logfile, "%s ", buf);
375
        }
376
        print_prefix = strstr(fmt, "\n") != NULL;
377
        vfprintf(logfile, fmt, vargs);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
378
        fflush(logfile);
379
    }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
380
}
381
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
382
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
383
{
384
    va_list vargs;
385
    va_start(vargs, fmt);
386
    http_vlog(fmt, vargs);
387
    va_end(vargs);
388
}
389
390
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
391
{
392
    static int print_prefix = 1;
393
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
394
    if (level > av_log_get_level())
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
395
        return;
396
    if (print_prefix && avc)
397
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
398
    print_prefix = strstr(fmt, "\n") != NULL;
399
    http_vlog(fmt, vargs);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
400
}
401
402
static void log_connection(HTTPContext *c)
403
{
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
404
    if (c->suppress_log)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
405
        return;
406
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
407
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
408
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
409
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
410
}
411
412
static void update_datarate(DataRateData *drd, int64_t count)
413
{
414
    if (!drd->time1 && !drd->count1) {
415
        drd->time1 = drd->time2 = cur_time;
416
        drd->count1 = drd->count2 = count;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
417
    } else if (cur_time - drd->time2 > 5000) {
418
        drd->time1 = drd->time2;
419
        drd->count1 = drd->count2;
420
        drd->time2 = cur_time;
421
        drd->count2 = count;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
422
    }
423
}
424
425
/* In bytes per second */
426
static int compute_datarate(DataRateData *drd, int64_t count)
427
{
428
    if (cur_time == drd->time1)
429
        return 0;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
430
1 by Daniel T Chen
Import upstream version 0.cvs20050918
431
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
432
}
433
434
435
static void start_children(FFStream *feed)
436
{
437
    if (no_launch)
438
        return;
439
440
    for (; feed; feed = feed->next) {
441
        if (feed->child_argv && !feed->pid) {
442
            feed->pid_start = time(0);
443
444
            feed->pid = fork();
445
446
            if (feed->pid < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
447
                http_log("Unable to create children\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
448
                exit(1);
449
            }
450
            if (!feed->pid) {
451
                /* In child */
452
                char pathname[1024];
453
                char *slash;
454
                int i;
455
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
456
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
457
458
                slash = strrchr(pathname, '/');
459
                if (!slash)
460
                    slash = pathname;
461
                else
462
                    slash++;
463
                strcpy(slash, "ffmpeg");
464
465
                http_log("Launch commandline: ");
466
                http_log("%s ", pathname);
467
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
468
                    http_log("%s ", feed->child_argv[i]);
469
                http_log("\n");
470
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
471
                for (i = 3; i < 256; i++)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
472
                    close(i);
473
474
                if (!ffserver_debug) {
475
                    i = open("/dev/null", O_RDWR);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
476
                    if (i != -1) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
477
                        dup2(i, 0);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
478
                        dup2(i, 1);
479
                        dup2(i, 2);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
480
                        close(i);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
481
                    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
482
                }
483
484
                /* This is needed to make relative pathnames work */
485
                chdir(my_program_dir);
486
487
                signal(SIGPIPE, SIG_DFL);
488
489
                execvp(pathname, feed->child_argv);
490
491
                _exit(1);
492
            }
493
        }
494
    }
495
}
496
497
/* open a listening socket */
498
static int socket_open_listen(struct sockaddr_in *my_addr)
499
{
500
    int server_fd, tmp;
501
502
    server_fd = socket(AF_INET,SOCK_STREAM,0);
503
    if (server_fd < 0) {
504
        perror ("socket");
505
        return -1;
506
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
507
1 by Daniel T Chen
Import upstream version 0.cvs20050918
508
    tmp = 1;
509
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
510
511
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
512
        char bindmsg[32];
513
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
514
        perror (bindmsg);
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
515
        closesocket(server_fd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
516
        return -1;
517
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
518
1 by Daniel T Chen
Import upstream version 0.cvs20050918
519
    if (listen (server_fd, 5) < 0) {
520
        perror ("listen");
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
521
        closesocket(server_fd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
522
        return -1;
523
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
524
    ff_socket_nonblock(server_fd, 1);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
525
526
    return server_fd;
527
}
528
529
/* start all multicast streams */
530
static void start_multicast(void)
531
{
532
    FFStream *stream;
533
    char session_id[32];
534
    HTTPContext *rtp_c;
535
    struct sockaddr_in dest_addr;
536
    int default_port, stream_index;
537
538
    default_port = 6000;
539
    for(stream = first_stream; stream != NULL; stream = stream->next) {
540
        if (stream->is_multicast) {
541
            /* open the RTP connection */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
542
            snprintf(session_id, sizeof(session_id), "%08x%08x",
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
543
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
544
545
            /* choose a port if none given */
546
            if (stream->multicast_port == 0) {
547
                stream->multicast_port = default_port;
548
                default_port += 100;
549
            }
550
551
            dest_addr.sin_family = AF_INET;
552
            dest_addr.sin_addr = stream->multicast_ip;
553
            dest_addr.sin_port = htons(stream->multicast_port);
554
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
555
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
556
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
557
            if (!rtp_c)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
558
                continue;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
559
1 by Daniel T Chen
Import upstream version 0.cvs20050918
560
            if (open_input_stream(rtp_c, "") < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
561
                http_log("Could not open input stream for stream '%s'\n",
562
                         stream->filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
563
                continue;
564
            }
565
566
            /* open each RTP stream */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
567
            for(stream_index = 0; stream_index < stream->nb_streams;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
568
                stream_index++) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
569
                dest_addr.sin_port = htons(stream->multicast_port +
1 by Daniel T Chen
Import upstream version 0.cvs20050918
570
                                           2 * stream_index);
571
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
572
                    http_log("Could not open output stream '%s/streamid=%d'\n",
573
                             stream->filename, stream_index);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
574
                    exit(1);
575
                }
576
            }
577
578
            /* change state to send data */
579
            rtp_c->state = HTTPSTATE_SEND_DATA;
580
        }
581
    }
582
}
583
584
/* main loop of the http server */
585
static int http_server(void)
586
{
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
587
    int server_fd = 0, rtsp_server_fd = 0;
588
    int ret, delay, delay1;
589
    struct pollfd *poll_table, *poll_entry;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
590
    HTTPContext *c, *c_next;
591
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
592
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
593
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
594
        return -1;
595
    }
596
597
    if (my_http_addr.sin_port) {
598
        server_fd = socket_open_listen(&my_http_addr);
599
        if (server_fd < 0)
600
            return -1;
601
    }
602
603
    if (my_rtsp_addr.sin_port) {
604
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
605
        if (rtsp_server_fd < 0)
606
            return -1;
607
    }
608
609
    if (!rtsp_server_fd && !server_fd) {
610
        http_log("HTTP and RTSP disabled.\n");
611
        return -1;
612
    }
613
614
    http_log("FFserver started.\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
615
616
    start_children(first_feed);
617
618
    start_multicast();
619
620
    for(;;) {
621
        poll_entry = poll_table;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
622
        if (server_fd) {
623
            poll_entry->fd = server_fd;
624
            poll_entry->events = POLLIN;
625
            poll_entry++;
626
        }
627
        if (rtsp_server_fd) {
628
            poll_entry->fd = rtsp_server_fd;
629
            poll_entry->events = POLLIN;
630
            poll_entry++;
631
        }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
632
633
        /* wait for events on each HTTP handle */
634
        c = first_http_ctx;
635
        delay = 1000;
636
        while (c != NULL) {
637
            int fd;
638
            fd = c->fd;
639
            switch(c->state) {
640
            case HTTPSTATE_SEND_HEADER:
641
            case RTSPSTATE_SEND_REPLY:
642
            case RTSPSTATE_SEND_PACKET:
643
                c->poll_entry = poll_entry;
644
                poll_entry->fd = fd;
645
                poll_entry->events = POLLOUT;
646
                poll_entry++;
647
                break;
648
            case HTTPSTATE_SEND_DATA_HEADER:
649
            case HTTPSTATE_SEND_DATA:
650
            case HTTPSTATE_SEND_DATA_TRAILER:
651
                if (!c->is_packetized) {
652
                    /* for TCP, we output as much as we can (may need to put a limit) */
653
                    c->poll_entry = poll_entry;
654
                    poll_entry->fd = fd;
655
                    poll_entry->events = POLLOUT;
656
                    poll_entry++;
657
                } else {
658
                    /* when ffserver is doing the timing, we work by
659
                       looking at which packet need to be sent every
660
                       10 ms */
661
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
662
                    if (delay1 < delay)
663
                        delay = delay1;
664
                }
665
                break;
666
            case HTTPSTATE_WAIT_REQUEST:
667
            case HTTPSTATE_RECEIVE_DATA:
668
            case HTTPSTATE_WAIT_FEED:
669
            case RTSPSTATE_WAIT_REQUEST:
670
                /* need to catch errors */
671
                c->poll_entry = poll_entry;
672
                poll_entry->fd = fd;
673
                poll_entry->events = POLLIN;/* Maybe this will work */
674
                poll_entry++;
675
                break;
676
            default:
677
                c->poll_entry = NULL;
678
                break;
679
            }
680
            c = c->next;
681
        }
682
683
        /* wait for an event on one connection. We poll at least every
684
           second to handle timeouts */
685
        do {
686
            ret = poll(poll_table, poll_entry - poll_table, delay);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
687
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
688
                ff_neterrno() != FF_NETERROR(EINTR))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
689
                return -1;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
690
        } while (ret < 0);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
691
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
692
        cur_time = av_gettime() / 1000;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
693
694
        if (need_to_start_children) {
695
            need_to_start_children = 0;
696
            start_children(first_feed);
697
        }
698
699
        /* now handle the events */
700
        for(c = first_http_ctx; c != NULL; c = c_next) {
701
            c_next = c->next;
702
            if (handle_connection(c) < 0) {
703
                /* close and free the connection */
704
                log_connection(c);
705
                close_connection(c);
706
            }
707
        }
708
709
        poll_entry = poll_table;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
710
        if (server_fd) {
711
            /* new HTTP connection request ? */
712
            if (poll_entry->revents & POLLIN)
713
                new_connection(server_fd, 0);
714
            poll_entry++;
715
        }
716
        if (rtsp_server_fd) {
717
            /* new RTSP connection request ? */
718
            if (poll_entry->revents & POLLIN)
719
                new_connection(rtsp_server_fd, 1);
720
        }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
721
    }
722
}
723
724
/* start waiting for a new HTTP/RTSP request */
725
static void start_wait_request(HTTPContext *c, int is_rtsp)
726
{
727
    c->buffer_ptr = c->buffer;
728
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
729
730
    if (is_rtsp) {
731
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
732
        c->state = RTSPSTATE_WAIT_REQUEST;
733
    } else {
734
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
735
        c->state = HTTPSTATE_WAIT_REQUEST;
736
    }
737
}
738
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
739
static void http_send_too_busy_reply(int fd)
740
{
741
    char buffer[300];
742
    int len = snprintf(buffer, sizeof(buffer),
743
                       "HTTP/1.0 200 Server too busy\r\n"
744
                       "Content-type: text/html\r\n"
745
                       "\r\n"
746
                       "<html><head><title>Too busy</title></head><body>\r\n"
747
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
748
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
749
                       "</body></html>\r\n",
750
                       nb_connections, nb_max_connections);
751
    send(fd, buffer, len, 0);
752
}
753
754
1 by Daniel T Chen
Import upstream version 0.cvs20050918
755
static void new_connection(int server_fd, int is_rtsp)
756
{
757
    struct sockaddr_in from_addr;
758
    int fd, len;
759
    HTTPContext *c = NULL;
760
761
    len = sizeof(from_addr);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
762
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
763
                &len);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
764
    if (fd < 0) {
765
        http_log("error during accept %s\n", strerror(errno));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
766
        return;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
767
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
768
    ff_socket_nonblock(fd, 1);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
769
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
770
    if (nb_connections >= nb_max_connections) {
771
        http_send_too_busy_reply(fd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
772
        goto fail;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
773
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
774
1 by Daniel T Chen
Import upstream version 0.cvs20050918
775
    /* add a new connection */
776
    c = av_mallocz(sizeof(HTTPContext));
777
    if (!c)
778
        goto fail;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
779
1 by Daniel T Chen
Import upstream version 0.cvs20050918
780
    c->fd = fd;
781
    c->poll_entry = NULL;
782
    c->from_addr = from_addr;
783
    c->buffer_size = IOBUFFER_INIT_SIZE;
784
    c->buffer = av_malloc(c->buffer_size);
785
    if (!c->buffer)
786
        goto fail;
787
788
    c->next = first_http_ctx;
789
    first_http_ctx = c;
790
    nb_connections++;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
791
1 by Daniel T Chen
Import upstream version 0.cvs20050918
792
    start_wait_request(c, is_rtsp);
793
794
    return;
795
796
 fail:
797
    if (c) {
798
        av_free(c->buffer);
799
        av_free(c);
800
    }
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
801
    closesocket(fd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
802
}
803
804
static void close_connection(HTTPContext *c)
805
{
806
    HTTPContext **cp, *c1;
807
    int i, nb_streams;
808
    AVFormatContext *ctx;
809
    URLContext *h;
810
    AVStream *st;
811
812
    /* remove connection from list */
813
    cp = &first_http_ctx;
814
    while ((*cp) != NULL) {
815
        c1 = *cp;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
816
        if (c1 == c)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
817
            *cp = c->next;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
818
        else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
819
            cp = &c1->next;
820
    }
821
822
    /* remove references, if any (XXX: do it faster) */
823
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
824
        if (c1->rtsp_c == c)
825
            c1->rtsp_c = NULL;
826
    }
827
828
    /* remove connection associated resources */
829
    if (c->fd >= 0)
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
830
        closesocket(c->fd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
831
    if (c->fmt_in) {
832
        /* close each frame parser */
833
        for(i=0;i<c->fmt_in->nb_streams;i++) {
834
            st = c->fmt_in->streams[i];
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
835
            if (st->codec->codec)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
836
                avcodec_close(st->codec);
837
        }
838
        av_close_input_file(c->fmt_in);
839
    }
840
841
    /* free RTP output streams if any */
842
    nb_streams = 0;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
843
    if (c->stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
844
        nb_streams = c->stream->nb_streams;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
845
1 by Daniel T Chen
Import upstream version 0.cvs20050918
846
    for(i=0;i<nb_streams;i++) {
847
        ctx = c->rtp_ctx[i];
848
        if (ctx) {
849
            av_write_trailer(ctx);
1.1.13 by Reinhard Tartler
Import upstream version 0.6
850
            av_metadata_free(&ctx->metadata);
851
            av_free(ctx->streams[0]);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
852
            av_free(ctx);
853
        }
854
        h = c->rtp_handles[i];
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
855
        if (h)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
856
            url_close(h);
857
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
858
1 by Daniel T Chen
Import upstream version 0.cvs20050918
859
    ctx = &c->fmt_ctx;
860
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
861
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
862
        if (ctx->oformat) {
863
            /* prepare header */
864
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
865
                av_write_trailer(ctx);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
866
                av_freep(&c->pb_buffer);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
867
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
868
            }
869
        }
870
    }
871
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
872
    for(i=0; i<ctx->nb_streams; i++)
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
873
        av_free(ctx->streams[i]);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
874
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
875
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
876
        current_bandwidth -= c->stream->bandwidth;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
877
878
    /* signal that there is no feed if we are the feeder socket */
879
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
880
        c->stream->feed_opened = 0;
881
        close(c->feed_fd);
882
    }
883
1 by Daniel T Chen
Import upstream version 0.cvs20050918
884
    av_freep(&c->pb_buffer);
885
    av_freep(&c->packet_buffer);
886
    av_free(c->buffer);
887
    av_free(c);
888
    nb_connections--;
889
}
890
891
static int handle_connection(HTTPContext *c)
892
{
893
    int len, ret;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
894
1 by Daniel T Chen
Import upstream version 0.cvs20050918
895
    switch(c->state) {
896
    case HTTPSTATE_WAIT_REQUEST:
897
    case RTSPSTATE_WAIT_REQUEST:
898
        /* timeout ? */
899
        if ((c->timeout - cur_time) < 0)
900
            return -1;
901
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
902
            return -1;
903
904
        /* no need to read if no events */
905
        if (!(c->poll_entry->revents & POLLIN))
906
            return 0;
907
        /* read the data */
908
    read_loop:
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
909
        len = recv(c->fd, c->buffer_ptr, 1, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
910
        if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
911
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
912
                ff_neterrno() != FF_NETERROR(EINTR))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
913
                return -1;
914
        } else if (len == 0) {
915
            return -1;
916
        } else {
917
            /* search for end of request. */
918
            uint8_t *ptr;
919
            c->buffer_ptr += len;
920
            ptr = c->buffer_ptr;
921
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
922
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
923
                /* request found : parse it and reply */
924
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
925
                    ret = http_parse_request(c);
926
                } else {
927
                    ret = rtsp_parse_request(c);
928
                }
929
                if (ret < 0)
930
                    return -1;
931
            } else if (ptr >= c->buffer_end) {
932
                /* request too long: cannot do anything */
933
                return -1;
934
            } else goto read_loop;
935
        }
936
        break;
937
938
    case HTTPSTATE_SEND_HEADER:
939
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
940
            return -1;
941
942
        /* no need to write if no events */
943
        if (!(c->poll_entry->revents & POLLOUT))
944
            return 0;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
945
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
946
        if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
947
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
948
                ff_neterrno() != FF_NETERROR(EINTR)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
949
                /* error : close connection */
950
                av_freep(&c->pb_buffer);
951
                return -1;
952
            }
953
        } else {
954
            c->buffer_ptr += len;
955
            if (c->stream)
956
                c->stream->bytes_served += len;
957
            c->data_count += len;
958
            if (c->buffer_ptr >= c->buffer_end) {
959
                av_freep(&c->pb_buffer);
960
                /* if error, exit */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
961
                if (c->http_error)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
962
                    return -1;
963
                /* all the buffer was sent : synchronize to the incoming stream */
964
                c->state = HTTPSTATE_SEND_DATA_HEADER;
965
                c->buffer_ptr = c->buffer_end = c->buffer;
966
            }
967
        }
968
        break;
969
970
    case HTTPSTATE_SEND_DATA:
971
    case HTTPSTATE_SEND_DATA_HEADER:
972
    case HTTPSTATE_SEND_DATA_TRAILER:
973
        /* for packetized output, we consider we can always write (the
974
           input streams sets the speed). It may be better to verify
975
           that we do not rely too much on the kernel queues */
976
        if (!c->is_packetized) {
977
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
978
                return -1;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
979
1 by Daniel T Chen
Import upstream version 0.cvs20050918
980
            /* no need to read if no events */
981
            if (!(c->poll_entry->revents & POLLOUT))
982
                return 0;
983
        }
984
        if (http_send_data(c) < 0)
985
            return -1;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
986
        /* close connection if trailer sent */
987
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
988
            return -1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
989
        break;
990
    case HTTPSTATE_RECEIVE_DATA:
991
        /* no need to read if no events */
992
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
993
            return -1;
994
        if (!(c->poll_entry->revents & POLLIN))
995
            return 0;
996
        if (http_receive_data(c) < 0)
997
            return -1;
998
        break;
999
    case HTTPSTATE_WAIT_FEED:
1000
        /* no need to read if no events */
1001
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1002
            return -1;
1003
1004
        /* nothing to do, we'll be waken up by incoming feed packets */
1005
        break;
1006
1007
    case RTSPSTATE_SEND_REPLY:
1008
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1009
            av_freep(&c->pb_buffer);
1010
            return -1;
1011
        }
1012
        /* no need to write if no events */
1013
        if (!(c->poll_entry->revents & POLLOUT))
1014
            return 0;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1015
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1016
        if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1017
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1018
                ff_neterrno() != FF_NETERROR(EINTR)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1019
                /* error : close connection */
1020
                av_freep(&c->pb_buffer);
1021
                return -1;
1022
            }
1023
        } else {
1024
            c->buffer_ptr += len;
1025
            c->data_count += len;
1026
            if (c->buffer_ptr >= c->buffer_end) {
1027
                /* all the buffer was sent : wait for a new request */
1028
                av_freep(&c->pb_buffer);
1029
                start_wait_request(c, 1);
1030
            }
1031
        }
1032
        break;
1033
    case RTSPSTATE_SEND_PACKET:
1034
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1035
            av_freep(&c->packet_buffer);
1036
            return -1;
1037
        }
1038
        /* no need to write if no events */
1039
        if (!(c->poll_entry->revents & POLLOUT))
1040
            return 0;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1041
        len = send(c->fd, c->packet_buffer_ptr,
1042
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1043
        if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1044
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1045
                ff_neterrno() != FF_NETERROR(EINTR)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1046
                /* error : close connection */
1047
                av_freep(&c->packet_buffer);
1048
                return -1;
1049
            }
1050
        } else {
1051
            c->packet_buffer_ptr += len;
1052
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1053
                /* all the buffer was sent : wait for a new request */
1054
                av_freep(&c->packet_buffer);
1055
                c->state = RTSPSTATE_WAIT_REQUEST;
1056
            }
1057
        }
1058
        break;
1059
    case HTTPSTATE_READY:
1060
        /* nothing to do */
1061
        break;
1062
    default:
1063
        return -1;
1064
    }
1065
    return 0;
1066
}
1067
1068
static int extract_rates(char *rates, int ratelen, const char *request)
1069
{
1070
    const char *p;
1071
1072
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1073
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1074
            const char *q = p + 7;
1075
1076
            while (*q && *q != '\n' && isspace(*q))
1077
                q++;
1078
1079
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1080
                int stream_no;
1081
                int rate_no;
1082
1083
                q += 20;
1084
1085
                memset(rates, 0xff, ratelen);
1086
1087
                while (1) {
1088
                    while (*q && *q != '\n' && *q != ':')
1089
                        q++;
1090
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1091
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1092
                        break;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1093
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1094
                    stream_no--;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1095
                    if (stream_no < ratelen && stream_no >= 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1096
                        rates[stream_no] = rate_no;
1097
1098
                    while (*q && *q != '\n' && !isspace(*q))
1099
                        q++;
1100
                }
1101
1102
                return 1;
1103
            }
1104
        }
1105
        p = strchr(p, '\n');
1106
        if (!p)
1107
            break;
1108
1109
        p++;
1110
    }
1111
1112
    return 0;
1113
}
1114
1115
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1116
{
1117
    int i;
1118
    int best_bitrate = 100000000;
1119
    int best = -1;
1120
1121
    for (i = 0; i < feed->nb_streams; i++) {
1122
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1123
1124
        if (feed_codec->codec_id != codec->codec_id ||
1125
            feed_codec->sample_rate != codec->sample_rate ||
1126
            feed_codec->width != codec->width ||
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1127
            feed_codec->height != codec->height)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1128
            continue;
1129
1130
        /* Potential stream */
1131
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1132
        /* We want the fastest stream less than bit_rate, or the slowest
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1133
         * faster than bit_rate
1134
         */
1135
1136
        if (feed_codec->bit_rate <= bit_rate) {
1137
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1138
                best_bitrate = feed_codec->bit_rate;
1139
                best = i;
1140
            }
1141
        } else {
1142
            if (feed_codec->bit_rate < best_bitrate) {
1143
                best_bitrate = feed_codec->bit_rate;
1144
                best = i;
1145
            }
1146
        }
1147
    }
1148
1149
    return best;
1150
}
1151
1152
static int modify_current_stream(HTTPContext *c, char *rates)
1153
{
1154
    int i;
1155
    FFStream *req = c->stream;
1156
    int action_required = 0;
1157
1158
    /* Not much we can do for a feed */
1159
    if (!req->feed)
1160
        return 0;
1161
1162
    for (i = 0; i < req->nb_streams; i++) {
1163
        AVCodecContext *codec = req->streams[i]->codec;
1164
1165
        switch(rates[i]) {
1166
            case 0:
1167
                c->switch_feed_streams[i] = req->feed_streams[i];
1168
                break;
1169
            case 1:
1170
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1171
                break;
1172
            case 2:
1173
                /* Wants off or slow */
1174
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1175
#ifdef WANTS_OFF
1176
                /* This doesn't work well when it turns off the only stream! */
1177
                c->switch_feed_streams[i] = -2;
1178
                c->feed_streams[i] = -2;
1179
#endif
1180
                break;
1181
        }
1182
1183
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1184
            action_required = 1;
1185
    }
1186
1187
    return action_required;
1188
}
1189
1190
1191
static void do_switch_stream(HTTPContext *c, int i)
1192
{
1193
    if (c->switch_feed_streams[i] >= 0) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1194
#ifdef PHILIP
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1195
        c->feed_streams[i] = c->switch_feed_streams[i];
1196
#endif
1197
1198
        /* Now update the stream */
1199
    }
1200
    c->switch_feed_streams[i] = -1;
1201
}
1202
1203
/* XXX: factorize in utils.c ? */
1204
/* XXX: take care with different space meaning */
1205
static void skip_spaces(const char **pp)
1206
{
1207
    const char *p;
1208
    p = *pp;
1209
    while (*p == ' ' || *p == '\t')
1210
        p++;
1211
    *pp = p;
1212
}
1213
1214
static void get_word(char *buf, int buf_size, const char **pp)
1215
{
1216
    const char *p;
1217
    char *q;
1218
1219
    p = *pp;
1220
    skip_spaces(&p);
1221
    q = buf;
1222
    while (!isspace(*p) && *p != '\0') {
1223
        if ((q - buf) < buf_size - 1)
1224
            *q++ = *p;
1225
        p++;
1226
    }
1227
    if (buf_size > 0)
1228
        *q = '\0';
1229
    *pp = p;
1230
}
1231
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1232
static void get_arg(char *buf, int buf_size, const char **pp)
1233
{
1234
    const char *p;
1235
    char *q;
1236
    int quote;
1237
1238
    p = *pp;
1239
    while (isspace(*p)) p++;
1240
    q = buf;
1241
    quote = 0;
1242
    if (*p == '\"' || *p == '\'')
1243
        quote = *p++;
1244
    for(;;) {
1245
        if (quote) {
1246
            if (*p == quote)
1247
                break;
1248
        } else {
1249
            if (isspace(*p))
1250
                break;
1251
        }
1252
        if (*p == '\0')
1253
            break;
1254
        if ((q - buf) < buf_size - 1)
1255
            *q++ = *p;
1256
        p++;
1257
    }
1258
    *q = '\0';
1259
    if (quote && *p == quote)
1260
        p++;
1261
    *pp = p;
1262
}
1263
1264
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1265
                         const char *p, const char *filename, int line_num)
1266
{
1267
    char arg[1024];
1268
    IPAddressACL acl;
1269
    int errors = 0;
1270
1271
    get_arg(arg, sizeof(arg), &p);
1272
    if (strcasecmp(arg, "allow") == 0)
1273
        acl.action = IP_ALLOW;
1274
    else if (strcasecmp(arg, "deny") == 0)
1275
        acl.action = IP_DENY;
1276
    else {
1277
        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1278
                filename, line_num, arg);
1279
        errors++;
1280
    }
1281
1282
    get_arg(arg, sizeof(arg), &p);
1283
1284
    if (resolve_host(&acl.first, arg) != 0) {
1285
        fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1286
                filename, line_num, arg);
1287
        errors++;
1288
    } else
1289
        acl.last = acl.first;
1290
1291
    get_arg(arg, sizeof(arg), &p);
1292
1293
    if (arg[0]) {
1294
        if (resolve_host(&acl.last, arg) != 0) {
1295
            fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1296
                    filename, line_num, arg);
1297
            errors++;
1298
        }
1299
    }
1300
1301
    if (!errors) {
1302
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1303
        IPAddressACL **naclp = 0;
1304
1305
        acl.next = 0;
1306
        *nacl = acl;
1307
1308
        if (stream)
1309
            naclp = &stream->acl;
1310
        else if (feed)
1311
            naclp = &feed->acl;
1312
        else if (ext_acl)
1313
            naclp = &ext_acl;
1314
        else {
1315
            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1316
                    filename, line_num);
1317
            errors++;
1318
        }
1319
1320
        if (naclp) {
1321
            while (*naclp)
1322
                naclp = &(*naclp)->next;
1323
1324
            *naclp = nacl;
1325
        }
1326
    }
1327
}
1328
1329
1330
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1331
{
1332
    FILE* f;
1333
    char line[1024];
1334
    char  cmd[1024];
1335
    IPAddressACL *acl = NULL;
1336
    int line_num = 0;
1337
    const char *p;
1338
1339
    f = fopen(stream->dynamic_acl, "r");
1340
    if (!f) {
1341
        perror(stream->dynamic_acl);
1342
        return NULL;
1343
    }
1344
1345
    acl = av_mallocz(sizeof(IPAddressACL));
1346
1347
    /* Build ACL */
1348
    for(;;) {
1349
        if (fgets(line, sizeof(line), f) == NULL)
1350
            break;
1351
        line_num++;
1352
        p = line;
1353
        while (isspace(*p))
1354
            p++;
1355
        if (*p == '\0' || *p == '#')
1356
            continue;
1357
        get_arg(cmd, sizeof(cmd), &p);
1358
1359
        if (!strcasecmp(cmd, "ACL"))
1360
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1361
    }
1362
    fclose(f);
1363
    return acl;
1364
}
1365
1366
1367
static void free_acl_list(IPAddressACL *in_acl)
1368
{
1369
    IPAddressACL *pacl,*pacl2;
1370
1371
    pacl = in_acl;
1372
    while(pacl) {
1373
        pacl2 = pacl;
1374
        pacl = pacl->next;
1375
        av_freep(pacl2);
1376
    }
1377
}
1378
1379
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1380
{
1381
    enum IPAddressAction last_action = IP_DENY;
1382
    IPAddressACL *acl;
1383
    struct in_addr *src = &c->from_addr.sin_addr;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1384
    unsigned long src_addr = src->s_addr;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1385
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1386
    for (acl = in_acl; acl; acl = acl->next) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1387
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1388
            return (acl->action == IP_ALLOW) ? 1 : 0;
1389
        last_action = acl->action;
1390
    }
1391
1392
    /* Nothing matched, so return not the last action */
1393
    return (last_action == IP_DENY) ? 1 : 0;
1394
}
1395
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1396
static int validate_acl(FFStream *stream, HTTPContext *c)
1397
{
1398
    int ret = 0;
1399
    IPAddressACL *acl;
1400
1401
1402
    /* if stream->acl is null validate_acl_list will return 1 */
1403
    ret = validate_acl_list(stream->acl, c);
1404
1405
    if (stream->dynamic_acl[0]) {
1406
        acl = parse_dynamic_acl(stream, c);
1407
1408
        ret = validate_acl_list(acl, c);
1409
1410
        free_acl_list(acl);
1411
    }
1412
1413
    return ret;
1414
}
1415
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1416
/* compute the real filename of a file by matching it without its
1417
   extensions to all the stream filenames */
1418
static void compute_real_filename(char *filename, int max_size)
1419
{
1420
    char file1[1024];
1421
    char file2[1024];
1422
    char *p;
1423
    FFStream *stream;
1424
1425
    /* compute filename by matching without the file extensions */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1426
    av_strlcpy(file1, filename, sizeof(file1));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1427
    p = strrchr(file1, '.');
1428
    if (p)
1429
        *p = '\0';
1430
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1431
        av_strlcpy(file2, stream->filename, sizeof(file2));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1432
        p = strrchr(file2, '.');
1433
        if (p)
1434
            *p = '\0';
1435
        if (!strcmp(file1, file2)) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1436
            av_strlcpy(filename, stream->filename, max_size);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1437
            break;
1438
        }
1439
    }
1440
}
1441
1442
enum RedirType {
1443
    REDIR_NONE,
1444
    REDIR_ASX,
1445
    REDIR_RAM,
1446
    REDIR_ASF,
1447
    REDIR_RTSP,
1448
    REDIR_SDP,
1449
};
1450
1451
/* parse http request and prepare header */
1452
static int http_parse_request(HTTPContext *c)
1453
{
1454
    char *p;
1455
    enum RedirType redir_type;
1456
    char cmd[32];
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1457
    char info[1024], filename[1024];
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1458
    char url[1024], *q;
1459
    char protocol[32];
1460
    char msg[1024];
1461
    const char *mime_type;
1462
    FFStream *stream;
1463
    int i;
1464
    char ratebuf[32];
1465
    char *useragent = 0;
1466
1467
    p = c->buffer;
1468
    get_word(cmd, sizeof(cmd), (const char **)&p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1469
    av_strlcpy(c->method, cmd, sizeof(c->method));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1470
1471
    if (!strcmp(cmd, "GET"))
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1472
        c->post = 0;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1473
    else if (!strcmp(cmd, "POST"))
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1474
        c->post = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1475
    else
1476
        return -1;
1477
1478
    get_word(url, sizeof(url), (const char **)&p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1479
    av_strlcpy(c->url, url, sizeof(c->url));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1480
1481
    get_word(protocol, sizeof(protocol), (const char **)&p);
1482
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1483
        return -1;
1484
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1485
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1486
1487
    if (ffserver_debug)
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1488
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1489
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1490
    /* find the filename and the optional info string in the request */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1491
    p = strchr(url, '?');
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1492
    if (p) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1493
        av_strlcpy(info, p, sizeof(info));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1494
        *p = '\0';
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1495
    } else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1496
        info[0] = '\0';
1497
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1498
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1499
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1500
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1501
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1502
            useragent = p + 11;
1503
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1504
                useragent++;
1505
            break;
1506
        }
1507
        p = strchr(p, '\n');
1508
        if (!p)
1509
            break;
1510
1511
        p++;
1512
    }
1513
1514
    redir_type = REDIR_NONE;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1515
    if (av_match_ext(filename, "asx")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1516
        redir_type = REDIR_ASX;
1517
        filename[strlen(filename)-1] = 'f';
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1518
    } else if (av_match_ext(filename, "asf") &&
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1519
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1520
        /* if this isn't WMP or lookalike, return the redirector file */
1521
        redir_type = REDIR_ASF;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1522
    } else if (av_match_ext(filename, "rpm,ram")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1523
        redir_type = REDIR_RAM;
1524
        strcpy(filename + strlen(filename)-2, "m");
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1525
    } else if (av_match_ext(filename, "rtsp")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1526
        redir_type = REDIR_RTSP;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1527
        compute_real_filename(filename, sizeof(filename) - 1);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1528
    } else if (av_match_ext(filename, "sdp")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1529
        redir_type = REDIR_SDP;
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1530
        compute_real_filename(filename, sizeof(filename) - 1);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1531
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1532
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1533
    // "redirect" / request to index.html
1534
    if (!strlen(filename))
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1535
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1536
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1537
    stream = first_stream;
1538
    while (stream != NULL) {
1539
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1540
            break;
1541
        stream = stream->next;
1542
    }
1543
    if (stream == NULL) {
1544
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1545
        http_log("File '%s' not found\n", url);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1546
        goto send_error;
1547
    }
1548
1549
    c->stream = stream;
1550
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1551
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1552
1553
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1554
        c->http_error = 301;
1555
        q = c->buffer;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1556
        q += snprintf(q, c->buffer_size,
1557
                      "HTTP/1.0 301 Moved\r\n"
1558
                      "Location: %s\r\n"
1559
                      "Content-type: text/html\r\n"
1560
                      "\r\n"
1561
                      "<html><head><title>Moved</title></head><body>\r\n"
1562
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1563
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1564
        /* prepare output buffer */
1565
        c->buffer_ptr = c->buffer;
1566
        c->buffer_end = q;
1567
        c->state = HTTPSTATE_SEND_HEADER;
1568
        return 0;
1569
    }
1570
1571
    /* If this is WMP, get the rate information */
1572
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1573
        if (modify_current_stream(c, ratebuf)) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1574
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1575
                if (c->switch_feed_streams[i] >= 0)
1576
                    do_switch_stream(c, i);
1577
            }
1578
        }
1579
    }
1580
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
1581
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1582
        current_bandwidth += stream->bandwidth;
1583
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1584
    /* If already streaming this feed, do not let start another feeder. */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1585
    if (stream->feed_opened) {
1586
        snprintf(msg, sizeof(msg), "This feed is already being received.");
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1587
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
1588
        goto send_error;
1589
    }
1590
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1591
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1592
        c->http_error = 200;
1593
        q = c->buffer;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1594
        q += snprintf(q, c->buffer_size,
1595
                      "HTTP/1.0 200 Server too busy\r\n"
1596
                      "Content-type: text/html\r\n"
1597
                      "\r\n"
1598
                      "<html><head><title>Too busy</title></head><body>\r\n"
1599
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1600
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1601
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1602
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1603
        /* prepare output buffer */
1604
        c->buffer_ptr = c->buffer;
1605
        c->buffer_end = q;
1606
        c->state = HTTPSTATE_SEND_HEADER;
1607
        return 0;
1608
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1609
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1610
    if (redir_type != REDIR_NONE) {
1611
        char *hostinfo = 0;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1612
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1613
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1614
            if (strncasecmp(p, "Host:", 5) == 0) {
1615
                hostinfo = p + 5;
1616
                break;
1617
            }
1618
            p = strchr(p, '\n');
1619
            if (!p)
1620
                break;
1621
1622
            p++;
1623
        }
1624
1625
        if (hostinfo) {
1626
            char *eoh;
1627
            char hostbuf[260];
1628
1629
            while (isspace(*hostinfo))
1630
                hostinfo++;
1631
1632
            eoh = strchr(hostinfo, '\n');
1633
            if (eoh) {
1634
                if (eoh[-1] == '\r')
1635
                    eoh--;
1636
1637
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1638
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1639
                    hostbuf[eoh - hostinfo] = 0;
1640
1641
                    c->http_error = 200;
1642
                    q = c->buffer;
1643
                    switch(redir_type) {
1644
                    case REDIR_ASX:
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1645
                        q += snprintf(q, c->buffer_size,
1646
                                      "HTTP/1.0 200 ASX Follows\r\n"
1647
                                      "Content-type: video/x-ms-asf\r\n"
1648
                                      "\r\n"
1649
                                      "<ASX Version=\"3\">\r\n"
1650
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1651
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1652
                                      "</ASX>\r\n", hostbuf, filename, info);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1653
                        break;
1654
                    case REDIR_RAM:
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1655
                        q += snprintf(q, c->buffer_size,
1656
                                      "HTTP/1.0 200 RAM Follows\r\n"
1657
                                      "Content-type: audio/x-pn-realaudio\r\n"
1658
                                      "\r\n"
1659
                                      "# Autogenerated by ffserver\r\n"
1660
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1661
                        break;
1662
                    case REDIR_ASF:
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1663
                        q += snprintf(q, c->buffer_size,
1664
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1665
                                      "Content-type: video/x-ms-asf\r\n"
1666
                                      "\r\n"
1667
                                      "[Reference]\r\n"
1668
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1669
                        break;
1670
                    case REDIR_RTSP:
1671
                        {
1672
                            char hostname[256], *p;
1673
                            /* extract only hostname */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1674
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1675
                            p = strrchr(hostname, ':');
1676
                            if (p)
1677
                                *p = '\0';
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1678
                            q += snprintf(q, c->buffer_size,
1679
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1680
                                          /* XXX: incorrect mime type ? */
1681
                                          "Content-type: application/x-rtsp\r\n"
1682
                                          "\r\n"
1683
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1684
                        }
1685
                        break;
1686
                    case REDIR_SDP:
1687
                        {
1688
                            uint8_t *sdp_data;
1689
                            int sdp_data_size, len;
1690
                            struct sockaddr_in my_addr;
1691
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1692
                            q += snprintf(q, c->buffer_size,
1693
                                          "HTTP/1.0 200 OK\r\n"
1694
                                          "Content-type: application/sdp\r\n"
1695
                                          "\r\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1696
1697
                            len = sizeof(my_addr);
1698
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1699
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1700
                            /* XXX: should use a dynamic buffer */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1701
                            sdp_data_size = prepare_sdp_description(stream,
1702
                                                                    &sdp_data,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1703
                                                                    my_addr.sin_addr);
1704
                            if (sdp_data_size > 0) {
1705
                                memcpy(q, sdp_data, sdp_data_size);
1706
                                q += sdp_data_size;
1707
                                *q = '\0';
1708
                                av_free(sdp_data);
1709
                            }
1710
                        }
1711
                        break;
1712
                    default:
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1713
                        abort();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1714
                        break;
1715
                    }
1716
1717
                    /* prepare output buffer */
1718
                    c->buffer_ptr = c->buffer;
1719
                    c->buffer_end = q;
1720
                    c->state = HTTPSTATE_SEND_HEADER;
1721
                    return 0;
1722
                }
1723
            }
1724
        }
1725
1726
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1727
        goto send_error;
1728
    }
1729
1730
    stream->conns_served++;
1731
1732
    /* XXX: add there authenticate and IP match */
1733
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1734
    if (c->post) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1735
        /* if post, it means a feed is being sent */
1736
        if (!stream->is_feed) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1737
            /* However it might be a status report from WMP! Let us log the
1738
             * data as it might come in handy one day. */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1739
            char *logline = 0;
1740
            int client_id = 0;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1741
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1742
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1743
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1744
                    logline = p;
1745
                    break;
1746
                }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1747
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1748
                    client_id = strtol(p + 18, 0, 10);
1749
                p = strchr(p, '\n');
1750
                if (!p)
1751
                    break;
1752
1753
                p++;
1754
            }
1755
1756
            if (logline) {
1757
                char *eol = strchr(logline, '\n');
1758
1759
                logline += 17;
1760
1761
                if (eol) {
1762
                    if (eol[-1] == '\r')
1763
                        eol--;
1764
                    http_log("%.*s\n", (int) (eol - logline), logline);
1765
                    c->suppress_log = 1;
1766
                }
1767
            }
1768
1769
#ifdef DEBUG_WMP
1770
            http_log("\nGot request:\n%s\n", c->buffer);
1771
#endif
1772
1773
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1774
                HTTPContext *wmpc;
1775
1776
                /* Now we have to find the client_id */
1777
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1778
                    if (wmpc->wmp_client_id == client_id)
1779
                        break;
1780
                }
1781
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1782
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1783
                    wmpc->switch_pending = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1784
            }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1785
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1786
            snprintf(msg, sizeof(msg), "POST command not handled");
1787
            c->stream = 0;
1788
            goto send_error;
1789
        }
1790
        if (http_start_receive_data(c) < 0) {
1791
            snprintf(msg, sizeof(msg), "could not open feed");
1792
            goto send_error;
1793
        }
1794
        c->http_error = 0;
1795
        c->state = HTTPSTATE_RECEIVE_DATA;
1796
        return 0;
1797
    }
1798
1799
#ifdef DEBUG_WMP
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1800
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1801
        http_log("\nGot request:\n%s\n", c->buffer);
1802
#endif
1803
1804
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1805
        goto send_status;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1806
1807
    /* open input stream */
1808
    if (open_input_stream(c, info) < 0) {
1809
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1810
        goto send_error;
1811
    }
1812
1813
    /* prepare http header */
1814
    q = c->buffer;
1815
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1816
    mime_type = c->stream->fmt->mime_type;
1817
    if (!mime_type)
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1818
        mime_type = "application/x-octet-stream";
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1819
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1820
1821
    /* for asf, we need extra headers */
1822
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1823
        /* Need to allocate a client id */
1824
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1825
        c->wmp_client_id = av_lfg_get(&random_state);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1826
1827
        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);
1828
    }
1829
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1830
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1831
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1832
    /* prepare output buffer */
1833
    c->http_error = 0;
1834
    c->buffer_ptr = c->buffer;
1835
    c->buffer_end = q;
1836
    c->state = HTTPSTATE_SEND_HEADER;
1837
    return 0;
1838
 send_error:
1839
    c->http_error = 404;
1840
    q = c->buffer;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1841
    q += snprintf(q, c->buffer_size,
1842
                  "HTTP/1.0 404 Not Found\r\n"
1843
                  "Content-type: text/html\r\n"
1844
                  "\r\n"
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1845
                  "<html>\n"
1846
                  "<head><title>404 Not Found</title></head>\n"
1847
                  "<body>%s</body>\n"
1848
                  "</html>\n", msg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1849
    /* prepare output buffer */
1850
    c->buffer_ptr = c->buffer;
1851
    c->buffer_end = q;
1852
    c->state = HTTPSTATE_SEND_HEADER;
1853
    return 0;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1854
 send_status:
1855
    compute_status(c);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1856
    c->http_error = 200; /* horrible : we use this value to avoid
1857
                            going to the send data state */
1858
    c->state = HTTPSTATE_SEND_HEADER;
1859
    return 0;
1860
}
1861
1862
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1863
{
1864
    static const char *suffix = " kMGTP";
1865
    const char *s;
1866
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1867
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1868
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1869
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1870
}
1871
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1872
static void compute_status(HTTPContext *c)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1873
{
1874
    HTTPContext *c1;
1875
    FFStream *stream;
1876
    char *p;
1877
    time_t ti;
1878
    int i, len;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1879
    ByteIOContext *pb;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1880
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1881
    if (url_open_dyn_buf(&pb) < 0) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1882
        /* XXX: return an error ? */
1883
        c->buffer_ptr = c->buffer;
1884
        c->buffer_end = c->buffer;
1885
        return;
1886
    }
1887
1888
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1889
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1890
    url_fprintf(pb, "Pragma: no-cache\r\n");
1891
    url_fprintf(pb, "\r\n");
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1892
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1893
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1894
    if (c->stream->feed_filename[0])
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1895
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1896
    url_fprintf(pb, "</head>\n<body>");
1897
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1898
    /* format status */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1899
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1900
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1901
    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");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1902
    stream = first_stream;
1903
    while (stream != NULL) {
1904
        char sfilename[1024];
1905
        char *eosf;
1906
1907
        if (stream->feed != stream) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1908
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1909
            eosf = sfilename + strlen(sfilename);
1910
            if (eosf - sfilename >= 4) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1911
                if (strcmp(eosf - 4, ".asf") == 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1912
                    strcpy(eosf - 4, ".asx");
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1913
                else if (strcmp(eosf - 3, ".rm") == 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1914
                    strcpy(eosf - 3, ".ram");
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1915
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1916
                    /* generate a sample RTSP director if
1917
                       unicast. Generate an SDP redirector if
1918
                       multicast */
1919
                    eosf = strrchr(sfilename, '.');
1920
                    if (!eosf)
1921
                        eosf = sfilename + strlen(sfilename);
1922
                    if (stream->is_multicast)
1923
                        strcpy(eosf, ".sdp");
1924
                    else
1925
                        strcpy(eosf, ".rtsp");
1926
                }
1927
            }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
1928
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1929
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1930
                         sfilename, stream->filename);
1931
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1932
                        stream->conns_served);
1933
            fmt_bytecount(pb, stream->bytes_served);
1934
            switch(stream->stream_type) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
1935
            case STREAM_TYPE_LIVE: {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1936
                    int audio_bit_rate = 0;
1937
                    int video_bit_rate = 0;
1938
                    const char *audio_codec_name = "";
1939
                    const char *video_codec_name = "";
1940
                    const char *audio_codec_name_extra = "";
1941
                    const char *video_codec_name_extra = "";
1942
1943
                    for(i=0;i<stream->nb_streams;i++) {
1944
                        AVStream *st = stream->streams[i];
1945
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1946
                        switch(st->codec->codec_type) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1947
                        case AVMEDIA_TYPE_AUDIO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1948
                            audio_bit_rate += st->codec->bit_rate;
1949
                            if (codec) {
1950
                                if (*audio_codec_name)
1951
                                    audio_codec_name_extra = "...";
1952
                                audio_codec_name = codec->name;
1953
                            }
1954
                            break;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1955
                        case AVMEDIA_TYPE_VIDEO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1956
                            video_bit_rate += st->codec->bit_rate;
1957
                            if (codec) {
1958
                                if (*video_codec_name)
1959
                                    video_codec_name_extra = "...";
1960
                                video_codec_name = codec->name;
1961
                            }
1962
                            break;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1963
                        case AVMEDIA_TYPE_DATA:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1964
                            video_bit_rate += st->codec->bit_rate;
1965
                            break;
1966
                        default:
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1967
                            abort();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1968
                        }
1969
                    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1970
                    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",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1971
                                 stream->fmt->name,
1972
                                 stream->bandwidth,
1973
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1974
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1975
                    if (stream->feed)
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1976
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
1977
                    else
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1978
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1979
                    url_fprintf(pb, "\n");
1980
                }
1981
                break;
1982
            default:
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1983
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1984
                break;
1985
            }
1986
        }
1987
        stream = stream->next;
1988
    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
1989
    url_fprintf(pb, "</table>\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
1990
1991
    stream = first_stream;
1992
    while (stream != NULL) {
1993
        if (stream->feed == stream) {
1994
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1995
            if (stream->pid) {
1996
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1997
1998
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1999
                {
2000
                    FILE *pid_stat;
2001
                    char ps_cmd[64];
2002
2003
                    /* This is somewhat linux specific I guess */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2004
                    snprintf(ps_cmd, sizeof(ps_cmd),
2005
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2006
                             stream->pid);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2007
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2008
                    pid_stat = popen(ps_cmd, "r");
2009
                    if (pid_stat) {
2010
                        char cpuperc[10];
2011
                        char cpuused[64];
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2012
2013
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2014
                                   cpuused) == 2) {
2015
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2016
                                         cpuperc, cpuused);
2017
                        }
2018
                        fclose(pid_stat);
2019
                    }
2020
                }
2021
#endif
2022
2023
                url_fprintf(pb, "<p>");
2024
            }
2025
            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");
2026
2027
            for (i = 0; i < stream->nb_streams; i++) {
2028
                AVStream *st = stream->streams[i];
2029
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2030
                const char *type = "unknown";
2031
                char parameters[64];
2032
2033
                parameters[0] = 0;
2034
2035
                switch(st->codec->codec_type) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2036
                case AVMEDIA_TYPE_AUDIO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2037
                    type = "audio";
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2038
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2039
                    break;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2040
                case AVMEDIA_TYPE_VIDEO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2041
                    type = "video";
2042
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2043
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2044
                    break;
2045
                default:
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2046
                    abort();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2047
                }
2048
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2049
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2050
            }
2051
            url_fprintf(pb, "</table>\n");
2052
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2053
        }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2054
        stream = stream->next;
2055
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2056
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2057
    /* connection status */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2058
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2059
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2060
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2061
                 nb_connections, nb_max_connections);
2062
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2063
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2064
                 current_bandwidth, max_bandwidth);
2065
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2066
    url_fprintf(pb, "<table>\n");
2067
    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");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2068
    c1 = first_http_ctx;
2069
    i = 0;
2070
    while (c1 != NULL) {
2071
        int bitrate;
2072
        int j;
2073
2074
        bitrate = 0;
2075
        if (c1->stream) {
2076
            for (j = 0; j < c1->stream->nb_streams; j++) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2077
                if (!c1->stream->feed)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2078
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2079
                else if (c1->feed_streams[j] >= 0)
2080
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2081
            }
2082
        }
2083
2084
        i++;
2085
        p = inet_ntoa(c1->from_addr.sin_addr);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2086
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2087
                    i,
2088
                    c1->stream ? c1->stream->filename : "",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2089
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2090
                    p,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2091
                    c1->protocol,
2092
                    http_state[c1->state]);
2093
        fmt_bytecount(pb, bitrate);
2094
        url_fprintf(pb, "<td align=right>");
2095
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2096
        url_fprintf(pb, "<td align=right>");
2097
        fmt_bytecount(pb, c1->data_count);
2098
        url_fprintf(pb, "\n");
2099
        c1 = c1->next;
2100
    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2101
    url_fprintf(pb, "</table>\n");
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2102
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2103
    /* date */
2104
    ti = time(NULL);
2105
    p = ctime(&ti);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2106
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
2107
    url_fprintf(pb, "</body>\n</html>\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2108
2109
    len = url_close_dyn_buf(pb, &c->pb_buffer);
2110
    c->buffer_ptr = c->pb_buffer;
2111
    c->buffer_end = c->pb_buffer + len;
2112
}
2113
2114
/* check if the parser needs to be opened for stream i */
2115
static void open_parser(AVFormatContext *s, int i)
2116
{
2117
    AVStream *st = s->streams[i];
2118
    AVCodec *codec;
2119
2120
    if (!st->codec->codec) {
2121
        codec = avcodec_find_decoder(st->codec->codec_id);
2122
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2123
            st->codec->parse_only = 1;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2124
            if (avcodec_open(st->codec, codec) < 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2125
                st->codec->parse_only = 0;
2126
        }
2127
    }
2128
}
2129
2130
static int open_input_stream(HTTPContext *c, const char *info)
2131
{
2132
    char buf[128];
2133
    char input_filename[1024];
2134
    AVFormatContext *s;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2135
    int buf_size, i, ret;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2136
    int64_t stream_pos;
2137
2138
    /* find file name */
2139
    if (c->stream->feed) {
2140
        strcpy(input_filename, c->stream->feed->feed_filename);
2141
        buf_size = FFM_PACKET_SIZE;
2142
        /* compute position (absolute time) */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2143
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2144
            stream_pos = parse_date(buf, 0);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2145
            if (stream_pos == INT64_MIN)
2146
                return -1;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2147
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2148
            int prebuffer = strtol(buf, 0, 10);
2149
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2150
        } else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2151
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2152
    } else {
2153
        strcpy(input_filename, c->stream->feed_filename);
2154
        buf_size = 0;
2155
        /* compute position (relative time) */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2156
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2157
            stream_pos = parse_date(buf, 1);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2158
            if (stream_pos == INT64_MIN)
2159
                return -1;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2160
        } else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2161
            stream_pos = 0;
2162
    }
2163
    if (input_filename[0] == '\0')
2164
        return -1;
2165
2166
    /* open stream */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2167
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2168
                                  buf_size, c->stream->ap_in)) < 0) {
2169
        http_log("could not open %s: %d\n", input_filename, ret);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2170
        return -1;
2171
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2172
    s->flags |= AVFMT_FLAG_GENPTS;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2173
    c->fmt_in = s;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2174
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2175
        http_log("Could not find stream info '%s'\n", input_filename);
2176
        av_close_input_file(s);
2177
        return -1;
2178
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2179
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2180
    /* open each parser */
2181
    for(i=0;i<s->nb_streams;i++)
2182
        open_parser(s, i);
2183
2184
    /* choose stream as clock source (we favorize video stream if
2185
       present) for packet sending */
2186
    c->pts_stream_index = 0;
2187
    for(i=0;i<c->stream->nb_streams;i++) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2188
        if (c->pts_stream_index == 0 &&
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2189
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2190
            c->pts_stream_index = i;
2191
        }
2192
    }
2193
2194
#if 1
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2195
    if (c->fmt_in->iformat->read_seek)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2196
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2197
#endif
2198
    /* set the start time (needed for maxtime and RTP packet timing) */
2199
    c->start_time = cur_time;
2200
    c->first_pts = AV_NOPTS_VALUE;
2201
    return 0;
2202
}
2203
2204
/* return the server clock (in us) */
2205
static int64_t get_server_clock(HTTPContext *c)
2206
{
2207
    /* compute current pts value from system time */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
2208
    return (cur_time - c->start_time) * 1000;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2209
}
2210
2211
/* return the estimated time at which the current packet must be sent
2212
   (in us) */
2213
static int64_t get_packet_send_clock(HTTPContext *c)
2214
{
2215
    int bytes_left, bytes_sent, frame_bytes;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2216
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2217
    frame_bytes = c->cur_frame_bytes;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2218
    if (frame_bytes <= 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2219
        return c->cur_pts;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2220
    else {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2221
        bytes_left = c->buffer_end - c->buffer_ptr;
2222
        bytes_sent = frame_bytes - bytes_left;
2223
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2224
    }
2225
}
2226
2227
2228
static int http_prepare_data(HTTPContext *c)
2229
{
2230
    int i, len, ret;
2231
    AVFormatContext *ctx;
2232
2233
    av_freep(&c->pb_buffer);
2234
    switch(c->state) {
2235
    case HTTPSTATE_SEND_DATA_HEADER:
2236
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2237
        av_metadata_set2(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2238
        av_metadata_set2(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2239
        av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2240
        av_metadata_set2(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2241
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2242
        for(i=0;i<c->stream->nb_streams;i++) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2243
            AVStream *st;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2244
            AVStream *src;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2245
            st = av_mallocz(sizeof(AVStream));
2246
            c->fmt_ctx.streams[i] = st;
2247
            /* if file or feed, then just take streams from FFStream struct */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2248
            if (!c->stream->feed ||
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2249
                c->stream->feed == c->stream)
2250
                src = c->stream->streams[i];
2251
            else
2252
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2253
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2254
            *st = *src;
2255
            st->priv_data = 0;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2256
            st->codec->frame_number = 0; /* XXX: should be done in
2257
                                           AVStream, not in codec */
2258
        }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2259
        /* set output format parameters */
2260
        c->fmt_ctx.oformat = c->stream->fmt;
2261
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2262
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2263
        c->got_key_frame = 0;
2264
2265
        /* prepare header and save header data in a stream */
2266
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2267
            /* XXX: potential leak */
2268
            return -1;
2269
        }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2270
        c->fmt_ctx.pb->is_streamed = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2271
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2272
        /*
2273
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2274
         * Default value from FFmpeg
2275
         * Try to set it use configuration option
2276
         */
2277
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2278
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2279
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2280
        av_set_parameters(&c->fmt_ctx, NULL);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2281
        if (av_write_header(&c->fmt_ctx) < 0) {
2282
            http_log("Error writing output header\n");
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
2283
            return -1;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2284
        }
1.1.13 by Reinhard Tartler
Import upstream version 0.6
2285
        av_metadata_free(&c->fmt_ctx.metadata);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2286
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2287
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2288
        c->buffer_ptr = c->pb_buffer;
2289
        c->buffer_end = c->pb_buffer + len;
2290
2291
        c->state = HTTPSTATE_SEND_DATA;
2292
        c->last_packet_sent = 0;
2293
        break;
2294
    case HTTPSTATE_SEND_DATA:
2295
        /* find a new packet */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2296
        /* read a packet from the input stream */
2297
        if (c->stream->feed)
2298
            ffm_set_write_index(c->fmt_in,
2299
                                c->stream->feed->feed_write_index,
2300
                                c->stream->feed->feed_size);
2301
2302
        if (c->stream->max_time &&
2303
            c->stream->max_time + c->start_time - cur_time < 0)
2304
            /* We have timed out */
2305
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2306
        else {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2307
            AVPacket pkt;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2308
        redo:
2309
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2310
                if (c->stream->feed && c->stream->feed->feed_opened) {
2311
                    /* if coming from feed, it means we reached the end of the
2312
                       ffm file, so must wait for more data */
2313
                    c->state = HTTPSTATE_WAIT_FEED;
2314
                    return 1; /* state changed */
2315
                } else {
2316
                    if (c->stream->loop) {
2317
                        av_close_input_file(c->fmt_in);
2318
                        c->fmt_in = NULL;
2319
                        if (open_input_stream(c, "") < 0)
2320
                            goto no_loop;
2321
                        goto redo;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2322
                    } else {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2323
                    no_loop:
2324
                        /* must send trailer now because eof or error */
2325
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2326
                    }
2327
                }
2328
            } else {
2329
                int source_index = pkt.stream_index;
2330
                /* update first pts if needed */
2331
                if (c->first_pts == AV_NOPTS_VALUE) {
2332
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2333
                    c->start_time = cur_time;
2334
                }
2335
                /* send it to the appropriate stream */
2336
                if (c->stream->feed) {
2337
                    /* if coming from a feed, select the right stream */
2338
                    if (c->switch_pending) {
2339
                        c->switch_pending = 0;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2340
                        for(i=0;i<c->stream->nb_streams;i++) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2341
                            if (c->switch_feed_streams[i] == pkt.stream_index)
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2342
                                if (pkt.flags & AV_PKT_FLAG_KEY)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2343
                                    do_switch_stream(c, i);
2344
                            if (c->switch_feed_streams[i] >= 0)
2345
                                c->switch_pending = 1;
2346
                        }
2347
                    }
2348
                    for(i=0;i<c->stream->nb_streams;i++) {
1.1.13 by Reinhard Tartler
Import upstream version 0.6
2349
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2350
                            AVStream *st = c->fmt_in->streams[source_index];
2351
                            pkt.stream_index = i;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2352
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2353
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2354
                                 c->stream->nb_streams == 1))
2355
                                c->got_key_frame = 1;
2356
                            if (!c->stream->send_on_key || c->got_key_frame)
2357
                                goto send_it;
2358
                        }
2359
                    }
2360
                } else {
2361
                    AVCodecContext *codec;
2362
                    AVStream *ist, *ost;
2363
                send_it:
2364
                    ist = c->fmt_in->streams[source_index];
2365
                    /* specific handling for RTP: we use several
2366
                       output stream (one for each RTP
2367
                       connection). XXX: need more abstract handling */
2368
                    if (c->is_packetized) {
2369
                        /* compute send time and duration */
2370
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2371
                        if (ist->start_time != AV_NOPTS_VALUE)
2372
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2373
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2374
                        /* find RTP context */
2375
                        c->packet_stream_index = pkt.stream_index;
2376
                        ctx = c->rtp_ctx[c->packet_stream_index];
2377
                        if(!ctx) {
2378
                            av_free_packet(&pkt);
2379
                            break;
2380
                        }
2381
                        codec = ctx->streams[0]->codec;
2382
                        /* only one stream per RTP connection */
2383
                        pkt.stream_index = 0;
2384
                    } else {
2385
                        ctx = &c->fmt_ctx;
2386
                        /* Fudge here */
2387
                        codec = ctx->streams[pkt.stream_index]->codec;
2388
                    }
2389
2390
                    if (c->is_packetized) {
2391
                        int max_packet_size;
2392
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2393
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2394
                        else
2395
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2396
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2397
                    } else {
2398
                        ret = url_open_dyn_buf(&ctx->pb);
2399
                    }
2400
                    if (ret < 0) {
2401
                        /* XXX: potential leak */
2402
                        return -1;
2403
                    }
2404
                    ost = ctx->streams[pkt.stream_index];
2405
2406
                    ctx->pb->is_streamed = 1;
2407
                    if (pkt.dts != AV_NOPTS_VALUE)
2408
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2409
                    if (pkt.pts != AV_NOPTS_VALUE)
2410
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2411
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2412
                    if (av_write_frame(ctx, &pkt) < 0) {
2413
                        http_log("Error writing frame to output\n");
2414
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2415
                    }
2416
2417
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2418
                    c->cur_frame_bytes = len;
2419
                    c->buffer_ptr = c->pb_buffer;
2420
                    c->buffer_end = c->pb_buffer + len;
2421
2422
                    codec->frame_number++;
2423
                    if (len == 0) {
2424
                        av_free_packet(&pkt);
2425
                        goto redo;
2426
                    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2427
                }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2428
                av_free_packet(&pkt);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2429
            }
2430
        }
2431
        break;
2432
    default:
2433
    case HTTPSTATE_SEND_DATA_TRAILER:
2434
        /* last packet test ? */
2435
        if (c->last_packet_sent || c->is_packetized)
2436
            return -1;
2437
        ctx = &c->fmt_ctx;
2438
        /* prepare header */
2439
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2440
            /* XXX: potential leak */
2441
            return -1;
2442
        }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2443
        c->fmt_ctx.pb->is_streamed = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2444
        av_write_trailer(ctx);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2445
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2446
        c->buffer_ptr = c->pb_buffer;
2447
        c->buffer_end = c->pb_buffer + len;
2448
2449
        c->last_packet_sent = 1;
2450
        break;
2451
    }
2452
    return 0;
2453
}
2454
2455
/* should convert the format at the same time */
2456
/* send data starting at c->buffer_ptr to the output connection
2457
   (either UDP or TCP connection) */
2458
static int http_send_data(HTTPContext *c)
2459
{
2460
    int len, ret;
2461
2462
    for(;;) {
2463
        if (c->buffer_ptr >= c->buffer_end) {
2464
            ret = http_prepare_data(c);
2465
            if (ret < 0)
2466
                return -1;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2467
            else if (ret != 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2468
                /* state change requested */
2469
                break;
2470
        } else {
2471
            if (c->is_packetized) {
2472
                /* RTP data output */
2473
                len = c->buffer_end - c->buffer_ptr;
2474
                if (len < 4) {
2475
                    /* fail safe - should never happen */
2476
                fail1:
2477
                    c->buffer_ptr = c->buffer_end;
2478
                    return 0;
2479
                }
2480
                len = (c->buffer_ptr[0] << 24) |
2481
                    (c->buffer_ptr[1] << 16) |
2482
                    (c->buffer_ptr[2] << 8) |
2483
                    (c->buffer_ptr[3]);
2484
                if (len > (c->buffer_end - c->buffer_ptr))
2485
                    goto fail1;
2486
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2487
                    /* nothing to send yet: we can wait */
2488
                    return 0;
2489
                }
2490
2491
                c->data_count += len;
2492
                update_datarate(&c->datarate, c->data_count);
2493
                if (c->stream)
2494
                    c->stream->bytes_served += len;
2495
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2496
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2497
                    /* RTP packets are sent inside the RTSP TCP connection */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2498
                    ByteIOContext *pb;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2499
                    int interleaved_index, size;
2500
                    uint8_t header[4];
2501
                    HTTPContext *rtsp_c;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2502
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2503
                    rtsp_c = c->rtsp_c;
2504
                    /* if no RTSP connection left, error */
2505
                    if (!rtsp_c)
2506
                        return -1;
2507
                    /* if already sending something, then wait. */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2508
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2509
                        break;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2510
                    if (url_open_dyn_buf(&pb) < 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2511
                        goto fail1;
2512
                    interleaved_index = c->packet_stream_index * 2;
2513
                    /* RTCP packets are sent at odd indexes */
2514
                    if (c->buffer_ptr[1] == 200)
2515
                        interleaved_index++;
2516
                    /* write RTSP TCP header */
2517
                    header[0] = '$';
2518
                    header[1] = interleaved_index;
2519
                    header[2] = len >> 8;
2520
                    header[3] = len;
2521
                    put_buffer(pb, header, 4);
2522
                    /* write RTP packet data */
2523
                    c->buffer_ptr += 4;
2524
                    put_buffer(pb, c->buffer_ptr, len);
2525
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2526
                    /* prepare asynchronous TCP sending */
2527
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2528
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2529
                    c->buffer_ptr += len;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2530
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2531
                    /* send everything we can NOW */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
2532
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2534
                    if (len > 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2535
                        rtsp_c->packet_buffer_ptr += len;
2536
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2537
                        /* if we could not send all the data, we will
2538
                           send it later, so a new state is needed to
2539
                           "lock" the RTSP TCP connection */
2540
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2541
                        break;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2542
                    } else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2543
                        /* all data has been sent */
2544
                        av_freep(&c->packet_buffer);
2545
                } else {
2546
                    /* send RTP packet directly in UDP */
2547
                    c->buffer_ptr += 4;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2548
                    url_write(c->rtp_handles[c->packet_stream_index],
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2549
                              c->buffer_ptr, len);
2550
                    c->buffer_ptr += len;
2551
                    /* here we continue as we can send several packets per 10 ms slot */
2552
                }
2553
            } else {
2554
                /* TCP data output */
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
2555
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2556
                if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2557
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2558
                        ff_neterrno() != FF_NETERROR(EINTR))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2559
                        /* error : close connection */
2560
                        return -1;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2561
                    else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2562
                        return 0;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2563
                } else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2564
                    c->buffer_ptr += len;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2565
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2566
                c->data_count += len;
2567
                update_datarate(&c->datarate, c->data_count);
2568
                if (c->stream)
2569
                    c->stream->bytes_served += len;
2570
                break;
2571
            }
2572
        }
2573
    } /* for(;;) */
2574
    return 0;
2575
}
2576
2577
static int http_start_receive_data(HTTPContext *c)
2578
{
2579
    int fd;
2580
2581
    if (c->stream->feed_opened)
2582
        return -1;
2583
2584
    /* Don't permit writing to this one */
2585
    if (c->stream->readonly)
2586
        return -1;
2587
2588
    /* open feed */
2589
    fd = open(c->stream->feed_filename, O_RDWR);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2590
    if (fd < 0) {
2591
        http_log("Error opening feeder file: %s\n", strerror(errno));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2592
        return -1;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2593
    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2594
    c->feed_fd = fd;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2595
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2596
    if (c->stream->truncate) {
2597
        /* truncate feed file */
2598
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2599
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2600
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2601
    } else {
2602
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2603
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2604
            return -1;
2605
        }
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
2606
    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2607
2608
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2609
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2610
    lseek(fd, 0, SEEK_SET);
2611
2612
    /* init buffer input */
2613
    c->buffer_ptr = c->buffer;
2614
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2615
    c->stream->feed_opened = 1;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2616
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2617
    return 0;
2618
}
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2619
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2620
static int http_receive_data(HTTPContext *c)
2621
{
2622
    HTTPContext *c1;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2623
    int len, loop_run = 0;
2624
2625
    while (c->chunked_encoding && !c->chunk_size &&
2626
           c->buffer_end > c->buffer_ptr) {
2627
        /* read chunk header, if present */
2628
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2629
2630
        if (len < 0) {
2631
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2632
                ff_neterrno() != FF_NETERROR(EINTR))
2633
                /* error : close connection */
2634
                goto fail;
2635
        } else if (len == 0) {
2636
            /* end of connection : close it */
2637
            goto fail;
2638
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2639
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2640
            c->chunk_size = strtol(c->buffer, 0, 16);
2641
            if (c->chunk_size == 0) // end of stream
2642
                goto fail;
2643
            c->buffer_ptr = c->buffer;
2644
            break;
2645
        } else if (++loop_run > 10) {
2646
            /* no chunk header, abort */
2647
            goto fail;
2648
        } else {
2649
            c->buffer_ptr++;
2650
        }
2651
    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2652
2653
    if (c->buffer_end > c->buffer_ptr) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2654
        len = recv(c->fd, c->buffer_ptr,
2655
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2656
        if (len < 0) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2657
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2658
                ff_neterrno() != FF_NETERROR(EINTR))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2659
                /* error : close connection */
2660
                goto fail;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2661
        } else if (len == 0)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2662
            /* end of connection : close it */
2663
            goto fail;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2664
        else {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2665
            c->chunk_size -= len;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2666
            c->buffer_ptr += len;
2667
            c->data_count += len;
2668
            update_datarate(&c->datarate, c->data_count);
2669
        }
2670
    }
2671
2672
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2673
        if (c->buffer[0] != 'f' ||
2674
            c->buffer[1] != 'm') {
2675
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2676
            goto fail;
2677
        }
2678
    }
2679
2680
    if (c->buffer_ptr >= c->buffer_end) {
2681
        FFStream *feed = c->stream;
2682
        /* a packet has been received : write it in the store, except
2683
           if header */
2684
        if (c->data_count > FFM_PACKET_SIZE) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2685
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
2686
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2687
            /* XXX: use llseek or url_seek */
2688
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2689
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2690
                http_log("Error writing to feed file: %s\n", strerror(errno));
2691
                goto fail;
2692
            }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2693
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2694
            feed->feed_write_index += FFM_PACKET_SIZE;
2695
            /* update file size */
2696
            if (feed->feed_write_index > c->stream->feed_size)
2697
                feed->feed_size = feed->feed_write_index;
2698
2699
            /* handle wrap around if max file size reached */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2700
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2701
                feed->feed_write_index = FFM_PACKET_SIZE;
2702
2703
            /* write index */
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
2704
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2705
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2706
                goto fail;
2707
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2708
2709
            /* wake up any waiting connections */
2710
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2711
                if (c1->state == HTTPSTATE_WAIT_FEED &&
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2712
                    c1->stream->feed == c->stream->feed)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2713
                    c1->state = HTTPSTATE_SEND_DATA;
2714
            }
2715
        } else {
2716
            /* We have a header in our hands that contains useful data */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2717
            AVFormatContext *s = NULL;
2718
            ByteIOContext *pb;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2719
            AVInputFormat *fmt_in;
2720
            int i;
2721
2722
            /* use feed output format name to find corresponding input format */
2723
            fmt_in = av_find_input_format(feed->fmt->name);
2724
            if (!fmt_in)
2725
                goto fail;
2726
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2727
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2728
            pb->is_streamed = 1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2729
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2730
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2731
                av_free(pb);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2732
                goto fail;
2733
            }
2734
2735
            /* Now we have the actual streams */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2736
            if (s->nb_streams != feed->nb_streams) {
2737
                av_close_input_stream(s);
2738
                av_free(pb);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2739
                http_log("Feed '%s' stream number does not match registered feed\n",
2740
                         c->stream->feed_filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2741
                goto fail;
2742
            }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2743
2744
            for (i = 0; i < s->nb_streams; i++) {
2745
                AVStream *fst = feed->streams[i];
2746
                AVStream *st = s->streams[i];
2747
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2748
                if (fst->codec->extradata_size) {
2749
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2750
                    if (!fst->codec->extradata)
2751
                        goto fail;
2752
                    memcpy(fst->codec->extradata, st->codec->extradata,
2753
                           fst->codec->extradata_size);
2754
                }
2755
            }
2756
2757
            av_close_input_stream(s);
2758
            av_free(pb);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2759
        }
2760
        c->buffer_ptr = c->buffer;
2761
    }
2762
2763
    return 0;
2764
 fail:
2765
    c->stream->feed_opened = 0;
2766
    close(c->feed_fd);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
2767
    /* wake up any waiting connections to stop waiting for feed */
2768
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2769
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2770
            c1->stream->feed == c->stream->feed)
2771
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2772
    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2773
    return -1;
2774
}
2775
2776
/********************************************************************/
2777
/* RTSP handling */
2778
2779
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2780
{
2781
    const char *str;
2782
    time_t ti;
2783
    char *p;
2784
    char buf2[32];
2785
2786
    switch(error_number) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2787
    case RTSP_STATUS_OK:
2788
        str = "OK";
2789
        break;
2790
    case RTSP_STATUS_METHOD:
2791
        str = "Method Not Allowed";
2792
        break;
2793
    case RTSP_STATUS_BANDWIDTH:
2794
        str = "Not Enough Bandwidth";
2795
        break;
2796
    case RTSP_STATUS_SESSION:
2797
        str = "Session Not Found";
2798
        break;
2799
    case RTSP_STATUS_STATE:
2800
        str = "Method Not Valid in This State";
2801
        break;
2802
    case RTSP_STATUS_AGGREGATE:
2803
        str = "Aggregate operation not allowed";
2804
        break;
2805
    case RTSP_STATUS_ONLY_AGGREGATE:
2806
        str = "Only aggregate operation allowed";
2807
        break;
2808
    case RTSP_STATUS_TRANSPORT:
2809
        str = "Unsupported transport";
2810
        break;
2811
    case RTSP_STATUS_INTERNAL:
2812
        str = "Internal Server Error";
2813
        break;
2814
    case RTSP_STATUS_SERVICE:
2815
        str = "Service Unavailable";
2816
        break;
2817
    case RTSP_STATUS_VERSION:
2818
        str = "RTSP Version not supported";
2819
        break;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2820
    default:
2821
        str = "Unknown Error";
2822
        break;
2823
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2824
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2825
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2826
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2827
2828
    /* output GMT time */
2829
    ti = time(NULL);
2830
    p = ctime(&ti);
2831
    strcpy(buf2, p);
2832
    p = buf2 + strlen(p) - 1;
2833
    if (*p == '\n')
2834
        *p = '\0';
2835
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2836
}
2837
2838
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2839
{
2840
    rtsp_reply_header(c, error_number);
2841
    url_fprintf(c->pb, "\r\n");
2842
}
2843
2844
static int rtsp_parse_request(HTTPContext *c)
2845
{
2846
    const char *p, *p1, *p2;
2847
    char cmd[32];
2848
    char url[1024];
2849
    char protocol[32];
2850
    char line[1024];
2851
    int len;
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
2852
    RTSPMessageHeader header1, *header = &header1;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2853
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2854
    c->buffer_ptr[0] = '\0';
2855
    p = c->buffer;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2856
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2857
    get_word(cmd, sizeof(cmd), &p);
2858
    get_word(url, sizeof(url), &p);
2859
    get_word(protocol, sizeof(protocol), &p);
2860
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2861
    av_strlcpy(c->method, cmd, sizeof(c->method));
2862
    av_strlcpy(c->url, url, sizeof(c->url));
2863
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2864
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2865
    if (url_open_dyn_buf(&c->pb) < 0) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2866
        /* XXX: cannot do more */
2867
        c->pb = NULL; /* safety */
2868
        return -1;
2869
    }
2870
2871
    /* check version name */
2872
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2873
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2874
        goto the_end;
2875
    }
2876
2877
    /* parse each header line */
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
2878
    memset(header, 0, sizeof(*header));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2879
    /* skip to next line */
2880
    while (*p != '\n' && *p != '\0')
2881
        p++;
2882
    if (*p == '\n')
2883
        p++;
2884
    while (*p != '\0') {
1.1.13 by Reinhard Tartler
Import upstream version 0.6
2885
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2886
        if (!p1)
2887
            break;
2888
        p2 = p1;
2889
        if (p2 > p && p2[-1] == '\r')
2890
            p2--;
2891
        /* skip empty line */
2892
        if (p2 == p)
2893
            break;
2894
        len = p2 - p;
2895
        if (len > sizeof(line) - 1)
2896
            len = sizeof(line) - 1;
2897
        memcpy(line, p, len);
2898
        line[len] = '\0';
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2899
        ff_rtsp_parse_line(header, line, NULL);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2900
        p = p1 + 1;
2901
    }
2902
2903
    /* handle sequence number */
2904
    c->seq = header->seq;
2905
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2906
    if (!strcmp(cmd, "DESCRIBE"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2907
        rtsp_cmd_describe(c, url);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2908
    else if (!strcmp(cmd, "OPTIONS"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2909
        rtsp_cmd_options(c, url);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2910
    else if (!strcmp(cmd, "SETUP"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2911
        rtsp_cmd_setup(c, url, header);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2912
    else if (!strcmp(cmd, "PLAY"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2913
        rtsp_cmd_play(c, url, header);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2914
    else if (!strcmp(cmd, "PAUSE"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2915
        rtsp_cmd_pause(c, url, header);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2916
    else if (!strcmp(cmd, "TEARDOWN"))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2917
        rtsp_cmd_teardown(c, url, header);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2918
    else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2919
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2920
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2921
 the_end:
2922
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2923
    c->pb = NULL; /* safety */
2924
    if (len < 0) {
2925
        /* XXX: cannot do more */
2926
        return -1;
2927
    }
2928
    c->buffer_ptr = c->pb_buffer;
2929
    c->buffer_end = c->pb_buffer + len;
2930
    c->state = RTSPSTATE_SEND_REPLY;
2931
    return 0;
2932
}
2933
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2934
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2935
                                   struct in_addr my_ip)
2936
{
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2937
    AVFormatContext *avc;
2938
    AVStream avs[MAX_STREAMS];
2939
    int i;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2940
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
2941
    avc =  avformat_alloc_context();
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2942
    if (avc == NULL) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2943
        return -1;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2944
    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2945
    av_metadata_set2(&avc->metadata, "title",
2946
                     stream->title[0] ? stream->title : "No Title", 0);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2947
    avc->nb_streams = stream->nb_streams;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2948
    if (stream->is_multicast) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2949
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2950
                 inet_ntoa(stream->multicast_ip),
2951
                 stream->multicast_port, stream->multicast_ttl);
1.1.13 by Reinhard Tartler
Import upstream version 0.6
2952
    } else {
2953
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2954
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2955
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2956
    for(i = 0; i < stream->nb_streams; i++) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2957
        avc->streams[i] = &avs[i];
2958
        avc->streams[i]->codec = stream->streams[i]->codec;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2959
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2960
    *pbuffer = av_mallocz(2048);
2961
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
1.1.13 by Reinhard Tartler
Import upstream version 0.6
2962
    av_metadata_free(&avc->metadata);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2963
    av_free(avc);
2964
2965
    return strlen(*pbuffer);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2966
}
2967
2968
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2969
{
2970
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2971
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2972
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2973
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2974
    url_fprintf(c->pb, "\r\n");
2975
}
2976
2977
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2978
{
2979
    FFStream *stream;
2980
    char path1[1024];
2981
    const char *path;
2982
    uint8_t *content;
2983
    int content_length, len;
2984
    struct sockaddr_in my_addr;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
2985
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2986
    /* find which url is asked */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
2987
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2988
    path = path1;
2989
    if (*path == '/')
2990
        path++;
2991
2992
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
2993
        if (!stream->is_feed &&
2994
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
1 by Daniel T Chen
Import upstream version 0.cvs20050918
2995
            !strcmp(path, stream->filename)) {
2996
            goto found;
2997
        }
2998
    }
2999
    /* no stream found */
3000
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3001
    return;
3002
3003
 found:
3004
    /* prepare the media description in sdp format */
3005
3006
    /* get the host IP */
3007
    len = sizeof(my_addr);
3008
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3009
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3010
    if (content_length < 0) {
3011
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3012
        return;
3013
    }
3014
    rtsp_reply_header(c, RTSP_STATUS_OK);
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3015
    url_fprintf(c->pb, "Content-Base: %s/\r\n", url);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3016
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
3017
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
3018
    url_fprintf(c->pb, "\r\n");
3019
    put_buffer(c->pb, content, content_length);
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3020
    av_free(content);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3021
}
3022
3023
static HTTPContext *find_rtp_session(const char *session_id)
3024
{
3025
    HTTPContext *c;
3026
3027
    if (session_id[0] == '\0')
3028
        return NULL;
3029
3030
    for(c = first_http_ctx; c != NULL; c = c->next) {
3031
        if (!strcmp(c->session_id, session_id))
3032
            return c;
3033
    }
3034
    return NULL;
3035
}
3036
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3037
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3038
{
3039
    RTSPTransportField *th;
3040
    int i;
3041
3042
    for(i=0;i<h->nb_transports;i++) {
3043
        th = &h->transports[i];
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3044
        if (th->lower_transport == lower_transport)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3045
            return th;
3046
    }
3047
    return NULL;
3048
}
3049
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3050
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3051
                           RTSPMessageHeader *h)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3052
{
3053
    FFStream *stream;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3054
    int stream_index, rtp_port, rtcp_port;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3055
    char buf[1024];
3056
    char path1[1024];
3057
    const char *path;
3058
    HTTPContext *rtp_c;
3059
    RTSPTransportField *th;
3060
    struct sockaddr_in dest_addr;
3061
    RTSPActionServerSetup setup;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3062
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3063
    /* find which url is asked */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3064
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3065
    path = path1;
3066
    if (*path == '/')
3067
        path++;
3068
3069
    /* now check each stream */
3070
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3071
        if (!stream->is_feed &&
3072
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3073
            /* accept aggregate filenames only if single stream */
3074
            if (!strcmp(path, stream->filename)) {
3075
                if (stream->nb_streams != 1) {
3076
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3077
                    return;
3078
                }
3079
                stream_index = 0;
3080
                goto found;
3081
            }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3082
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3083
            for(stream_index = 0; stream_index < stream->nb_streams;
3084
                stream_index++) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3085
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3086
                         stream->filename, stream_index);
3087
                if (!strcmp(path, buf))
3088
                    goto found;
3089
            }
3090
        }
3091
    }
3092
    /* no stream found */
3093
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3094
    return;
3095
 found:
3096
3097
    /* generate session id if needed */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3098
    if (h->session_id[0] == '\0')
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
3099
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3100
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3101
3102
    /* find rtp session, and create it if none found */
3103
    rtp_c = find_rtp_session(h->session_id);
3104
    if (!rtp_c) {
3105
        /* always prefer UDP */
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3106
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3107
        if (!th) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3108
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3109
            if (!th) {
3110
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3111
                return;
3112
            }
3113
        }
3114
3115
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3116
                                   th->lower_transport);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3117
        if (!rtp_c) {
3118
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3119
            return;
3120
        }
3121
3122
        /* open input stream */
3123
        if (open_input_stream(rtp_c, "") < 0) {
3124
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3125
            return;
3126
        }
3127
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3128
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3129
    /* test if stream is OK (test needed because several SETUP needs
3130
       to be done for a given file) */
3131
    if (rtp_c->stream != stream) {
3132
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3133
        return;
3134
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3135
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3136
    /* test if stream is already set up */
3137
    if (rtp_c->rtp_ctx[stream_index]) {
3138
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3139
        return;
3140
    }
3141
3142
    /* check transport */
3143
    th = find_transport(h, rtp_c->rtp_protocol);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3144
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3145
                th->client_port_min <= 0)) {
3146
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3147
        return;
3148
    }
3149
3150
    /* setup default options */
3151
    setup.transport_option[0] = '\0';
3152
    dest_addr = rtp_c->from_addr;
3153
    dest_addr.sin_port = htons(th->client_port_min);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3154
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3155
    /* setup stream */
3156
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3157
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3158
        return;
3159
    }
3160
3161
    /* now everything is OK, so we can send the connection parameters */
3162
    rtsp_reply_header(c, RTSP_STATUS_OK);
3163
    /* session ID */
3164
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3165
3166
    switch(rtp_c->rtp_protocol) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3167
    case RTSP_LOWER_TRANSPORT_UDP:
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3168
        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3169
        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3170
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3171
                    "client_port=%d-%d;server_port=%d-%d",
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3172
                    th->client_port_min, th->client_port_max,
3173
                    rtp_port, rtcp_port);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3174
        break;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3175
    case RTSP_LOWER_TRANSPORT_TCP:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3176
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3177
                    stream_index * 2, stream_index * 2 + 1);
3178
        break;
3179
    default:
3180
        break;
3181
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3182
    if (setup.transport_option[0] != '\0')
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3183
        url_fprintf(c->pb, ";%s", setup.transport_option);
3184
    url_fprintf(c->pb, "\r\n");
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3185
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3186
3187
    url_fprintf(c->pb, "\r\n");
3188
}
3189
3190
3191
/* find an rtp connection by using the session ID. Check consistency
3192
   with filename */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3193
static HTTPContext *find_rtp_session_with_url(const char *url,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3194
                                              const char *session_id)
3195
{
3196
    HTTPContext *rtp_c;
3197
    char path1[1024];
3198
    const char *path;
3199
    char buf[1024];
3200
    int s;
3201
3202
    rtp_c = find_rtp_session(session_id);
3203
    if (!rtp_c)
3204
        return NULL;
3205
3206
    /* find which url is asked */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3207
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3208
    path = path1;
3209
    if (*path == '/')
3210
        path++;
3211
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3212
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3213
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3214
        rtp_c->stream->filename, s);
3215
      if(!strncmp(path, buf, sizeof(buf))) {
3216
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3217
        return rtp_c;
3218
      }
3219
    }
3220
    return NULL;
3221
}
3222
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3223
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3224
{
3225
    HTTPContext *rtp_c;
3226
3227
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3228
    if (!rtp_c) {
3229
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3230
        return;
3231
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3232
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3233
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3234
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3235
        rtp_c->state != HTTPSTATE_READY) {
3236
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3237
        return;
3238
    }
3239
3240
    rtp_c->state = HTTPSTATE_SEND_DATA;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3241
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3242
    /* now everything is OK, so we can send the connection parameters */
3243
    rtsp_reply_header(c, RTSP_STATUS_OK);
3244
    /* session ID */
3245
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3246
    url_fprintf(c->pb, "\r\n");
3247
}
3248
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3249
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3250
{
3251
    HTTPContext *rtp_c;
3252
3253
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3254
    if (!rtp_c) {
3255
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3256
        return;
3257
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3258
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3259
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3260
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3261
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3262
        return;
3263
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3264
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3265
    rtp_c->state = HTTPSTATE_READY;
3266
    rtp_c->first_pts = AV_NOPTS_VALUE;
3267
    /* now everything is OK, so we can send the connection parameters */
3268
    rtsp_reply_header(c, RTSP_STATUS_OK);
3269
    /* session ID */
3270
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3271
    url_fprintf(c->pb, "\r\n");
3272
}
3273
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3274
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3275
{
3276
    HTTPContext *rtp_c;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3277
    char session_id[32];
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3278
3279
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3280
    if (!rtp_c) {
3281
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3282
        return;
3283
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3284
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3285
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3286
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3287
    /* abort the session */
3288
    close_connection(rtp_c);
3289
3290
    /* now everything is OK, so we can send the connection parameters */
3291
    rtsp_reply_header(c, RTSP_STATUS_OK);
3292
    /* session ID */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3293
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3294
    url_fprintf(c->pb, "\r\n");
3295
}
3296
3297
3298
/********************************************************************/
3299
/* RTP handling */
3300
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3301
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3302
                                       FFStream *stream, const char *session_id,
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3303
                                       enum RTSPLowerTransport rtp_protocol)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3304
{
3305
    HTTPContext *c = NULL;
3306
    const char *proto_str;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3307
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3308
    /* XXX: should output a warning page when coming
3309
       close to the connection limit */
3310
    if (nb_connections >= nb_max_connections)
3311
        goto fail;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3312
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3313
    /* add a new connection */
3314
    c = av_mallocz(sizeof(HTTPContext));
3315
    if (!c)
3316
        goto fail;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3317
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3318
    c->fd = -1;
3319
    c->poll_entry = NULL;
3320
    c->from_addr = *from_addr;
3321
    c->buffer_size = IOBUFFER_INIT_SIZE;
3322
    c->buffer = av_malloc(c->buffer_size);
3323
    if (!c->buffer)
3324
        goto fail;
3325
    nb_connections++;
3326
    c->stream = stream;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3327
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3328
    c->state = HTTPSTATE_READY;
3329
    c->is_packetized = 1;
3330
    c->rtp_protocol = rtp_protocol;
3331
3332
    /* protocol is shown in statistics */
3333
    switch(c->rtp_protocol) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3334
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3335
        proto_str = "MCAST";
3336
        break;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3337
    case RTSP_LOWER_TRANSPORT_UDP:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3338
        proto_str = "UDP";
3339
        break;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3340
    case RTSP_LOWER_TRANSPORT_TCP:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3341
        proto_str = "TCP";
3342
        break;
3343
    default:
3344
        proto_str = "???";
3345
        break;
3346
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3347
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3348
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3349
3350
    current_bandwidth += stream->bandwidth;
3351
3352
    c->next = first_http_ctx;
3353
    first_http_ctx = c;
3354
    return c;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3355
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3356
 fail:
3357
    if (c) {
3358
        av_free(c->buffer);
3359
        av_free(c);
3360
    }
3361
    return NULL;
3362
}
3363
3364
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3365
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3366
   used. */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3367
static int rtp_new_av_stream(HTTPContext *c,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3368
                             int stream_index, struct sockaddr_in *dest_addr,
3369
                             HTTPContext *rtsp_c)
3370
{
3371
    AVFormatContext *ctx;
3372
    AVStream *st;
3373
    char *ipaddr;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3374
    URLContext *h = NULL;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3375
    uint8_t *dummy_buf;
3376
    int max_packet_size;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3377
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3378
    /* now we can open the relevant output stream */
1.1.8 by Reinhard Tartler
Import upstream version 0.svn20090303
3379
    ctx = avformat_alloc_context();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3380
    if (!ctx)
3381
        return -1;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3382
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3383
3384
    st = av_mallocz(sizeof(AVStream));
3385
    if (!st)
3386
        goto fail;
3387
    ctx->nb_streams = 1;
3388
    ctx->streams[0] = st;
3389
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3390
    if (!c->stream->feed ||
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3391
        c->stream->feed == c->stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3392
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3393
    else
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3394
        memcpy(st,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3395
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3396
               sizeof(AVStream));
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3397
    st->priv_data = NULL;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3398
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3399
    /* build destination RTP address */
3400
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3401
3402
    switch(c->rtp_protocol) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3403
    case RTSP_LOWER_TRANSPORT_UDP:
3404
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3405
        /* RTP/UDP case */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3406
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3407
        /* XXX: also pass as parameter to function ? */
3408
        if (c->stream->is_multicast) {
3409
            int ttl;
3410
            ttl = c->stream->multicast_ttl;
3411
            if (!ttl)
3412
                ttl = 16;
3413
            snprintf(ctx->filename, sizeof(ctx->filename),
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3414
                     "rtp://%s:%d?multicast=1&ttl=%d",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3415
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3416
        } else {
3417
            snprintf(ctx->filename, sizeof(ctx->filename),
3418
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3419
        }
3420
3421
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3422
            goto fail;
3423
        c->rtp_handles[stream_index] = h;
3424
        max_packet_size = url_get_max_packet_size(h);
3425
        break;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3426
    case RTSP_LOWER_TRANSPORT_TCP:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3427
        /* RTP/TCP case */
3428
        c->rtsp_c = rtsp_c;
3429
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3430
        break;
3431
    default:
3432
        goto fail;
3433
    }
3434
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3435
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3436
             ipaddr, ntohs(dest_addr->sin_port),
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3437
             c->stream->filename, stream_index, c->protocol);
3438
3439
    /* normally, no packets should be output here, but the packet size may be checked */
3440
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3441
        /* XXX: close stream */
3442
        goto fail;
3443
    }
3444
    av_set_parameters(ctx, NULL);
3445
    if (av_write_header(ctx) < 0) {
3446
    fail:
3447
        if (h)
3448
            url_close(h);
3449
        av_free(ctx);
3450
        return -1;
3451
    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3452
    url_close_dyn_buf(ctx->pb, &dummy_buf);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3453
    av_free(dummy_buf);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3454
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3455
    c->rtp_ctx[stream_index] = ctx;
3456
    return 0;
3457
}
3458
3459
/********************************************************************/
3460
/* ffserver initialization */
3461
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3462
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3463
{
3464
    AVStream *fst;
3465
3466
    fst = av_mallocz(sizeof(AVStream));
3467
    if (!fst)
3468
        return NULL;
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3469
    if (copy) {
3470
        fst->codec= avcodec_alloc_context();
3471
        memcpy(fst->codec, codec, sizeof(AVCodecContext));
3472
        if (codec->extradata_size) {
3473
            fst->codec->extradata = av_malloc(codec->extradata_size);
3474
            memcpy(fst->codec->extradata, codec->extradata,
3475
                codec->extradata_size);
3476
        }
3477
    } else {
3478
        /* live streams must use the actual feed's codec since it may be
3479
         * updated later to carry extradata needed by the streams.
3480
         */
3481
        fst->codec = codec;
3482
    }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3483
    fst->priv_data = av_mallocz(sizeof(FeedData));
3484
    fst->index = stream->nb_streams;
3485
    av_set_pts_info(fst, 33, 1, 90000);
3486
    stream->streams[stream->nb_streams++] = fst;
3487
    return fst;
3488
}
3489
3490
/* return the stream number in the feed */
3491
static int add_av_stream(FFStream *feed, AVStream *st)
3492
{
3493
    AVStream *fst;
3494
    AVCodecContext *av, *av1;
3495
    int i;
3496
3497
    av = st->codec;
3498
    for(i=0;i<feed->nb_streams;i++) {
3499
        st = feed->streams[i];
3500
        av1 = st->codec;
3501
        if (av1->codec_id == av->codec_id &&
3502
            av1->codec_type == av->codec_type &&
3503
            av1->bit_rate == av->bit_rate) {
3504
3505
            switch(av->codec_type) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3506
            case AVMEDIA_TYPE_AUDIO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3507
                if (av1->channels == av->channels &&
3508
                    av1->sample_rate == av->sample_rate)
3509
                    goto found;
3510
                break;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3511
            case AVMEDIA_TYPE_VIDEO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3512
                if (av1->width == av->width &&
3513
                    av1->height == av->height &&
3514
                    av1->time_base.den == av->time_base.den &&
3515
                    av1->time_base.num == av->time_base.num &&
3516
                    av1->gop_size == av->gop_size)
3517
                    goto found;
3518
                break;
3519
            default:
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3520
                abort();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3521
            }
3522
        }
3523
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3524
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3525
    fst = add_av_stream1(feed, av, 0);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3526
    if (!fst)
3527
        return -1;
3528
    return feed->nb_streams - 1;
3529
 found:
3530
    return i;
3531
}
3532
3533
static void remove_stream(FFStream *stream)
3534
{
3535
    FFStream **ps;
3536
    ps = &first_stream;
3537
    while (*ps != NULL) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3538
        if (*ps == stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3539
            *ps = (*ps)->next;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3540
        else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3541
            ps = &(*ps)->next;
3542
    }
3543
}
3544
3545
/* specific mpeg4 handling : we extract the raw parameters */
3546
static void extract_mpeg4_header(AVFormatContext *infile)
3547
{
3548
    int mpeg4_count, i, size;
3549
    AVPacket pkt;
3550
    AVStream *st;
3551
    const uint8_t *p;
3552
3553
    mpeg4_count = 0;
3554
    for(i=0;i<infile->nb_streams;i++) {
3555
        st = infile->streams[i];
3556
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3557
            st->codec->extradata_size == 0) {
3558
            mpeg4_count++;
3559
        }
3560
    }
3561
    if (!mpeg4_count)
3562
        return;
3563
3564
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3565
    while (mpeg4_count > 0) {
3566
        if (av_read_packet(infile, &pkt) < 0)
3567
            break;
3568
        st = infile->streams[pkt.stream_index];
3569
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3570
            st->codec->extradata_size == 0) {
3571
            av_freep(&st->codec->extradata);
3572
            /* fill extradata with the header */
3573
            /* XXX: we make hard suppositions here ! */
3574
            p = pkt.data;
3575
            while (p < pkt.data + pkt.size - 4) {
3576
                /* stop when vop header is found */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3577
                if (p[0] == 0x00 && p[1] == 0x00 &&
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3578
                    p[2] == 0x01 && p[3] == 0xb6) {
3579
                    size = p - pkt.data;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3580
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3581
                    st->codec->extradata = av_malloc(size);
3582
                    st->codec->extradata_size = size;
3583
                    memcpy(st->codec->extradata, pkt.data, size);
3584
                    break;
3585
                }
3586
                p++;
3587
            }
3588
            mpeg4_count--;
3589
        }
3590
        av_free_packet(&pkt);
3591
    }
3592
}
3593
3594
/* compute the needed AVStream for each file */
3595
static void build_file_streams(void)
3596
{
3597
    FFStream *stream, *stream_next;
3598
    AVFormatContext *infile;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3599
    int i, ret;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3600
3601
    /* gather all streams */
3602
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3603
        stream_next = stream->next;
3604
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3605
            !stream->feed) {
3606
            /* the stream comes from a file */
3607
            /* try to open the file */
3608
            /* open stream */
3609
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3610
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3611
                /* specific case : if transport stream output to RTP,
3612
                   we use a raw transport stream reader */
3613
                stream->ap_in->mpeg2ts_raw = 1;
3614
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3615
            }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3616
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3617
            http_log("Opening file '%s'\n", stream->feed_filename);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3618
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3619
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3620
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3621
                /* remove stream (no need to spend more time on it) */
3622
            fail:
3623
                remove_stream(stream);
3624
            } else {
3625
                /* find all the AVStreams inside and reference them in
3626
                   'stream' */
3627
                if (av_find_stream_info(infile) < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3628
                    http_log("Could not find codec parameters from '%s'\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3629
                             stream->feed_filename);
3630
                    av_close_input_file(infile);
3631
                    goto fail;
3632
                }
3633
                extract_mpeg4_header(infile);
3634
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3635
                for(i=0;i<infile->nb_streams;i++)
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3636
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3637
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3638
                av_close_input_file(infile);
3639
            }
3640
        }
3641
    }
3642
}
3643
3644
/* compute the needed AVStream for each feed */
3645
static void build_feed_streams(void)
3646
{
3647
    FFStream *stream, *feed;
3648
    int i;
3649
3650
    /* gather all streams */
3651
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3652
        feed = stream->feed;
3653
        if (feed) {
3654
            if (!stream->is_feed) {
3655
                /* we handle a stream coming from a feed */
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3656
                for(i=0;i<stream->nb_streams;i++)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3657
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3658
            }
3659
        }
3660
    }
3661
3662
    /* gather all streams */
3663
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3664
        feed = stream->feed;
3665
        if (feed) {
3666
            if (stream->is_feed) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3667
                for(i=0;i<stream->nb_streams;i++)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3668
                    stream->feed_streams[i] = i;
3669
            }
3670
        }
3671
    }
3672
3673
    /* create feed files if needed */
3674
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3675
        int fd;
3676
3677
        if (url_exist(feed->feed_filename)) {
3678
            /* See if it matches */
3679
            AVFormatContext *s;
3680
            int matches = 0;
3681
3682
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3683
                /* Now see if it matches */
3684
                if (s->nb_streams == feed->nb_streams) {
3685
                    matches = 1;
3686
                    for(i=0;i<s->nb_streams;i++) {
3687
                        AVStream *sf, *ss;
3688
                        sf = feed->streams[i];
3689
                        ss = s->streams[i];
3690
3691
                        if (sf->index != ss->index ||
3692
                            sf->id != ss->id) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3693
                            http_log("Index & Id do not match for stream %d (%s)\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3694
                                   i, feed->feed_filename);
3695
                            matches = 0;
3696
                        } else {
3697
                            AVCodecContext *ccf, *ccs;
3698
3699
                            ccf = sf->codec;
3700
                            ccs = ss->codec;
3701
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3702
1.1.13 by Reinhard Tartler
Import upstream version 0.6
3703
                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3704
                                http_log("Codecs do not match for stream %d\n", i);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3705
                                matches = 0;
3706
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3707
                                http_log("Codec bitrates do not match for stream %d\n", i);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3708
                                matches = 0;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3709
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3710
                                if (CHECK_CODEC(time_base.den) ||
3711
                                    CHECK_CODEC(time_base.num) ||
3712
                                    CHECK_CODEC(width) ||
3713
                                    CHECK_CODEC(height)) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3714
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3715
                                    matches = 0;
3716
                                }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3717
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3718
                                if (CHECK_CODEC(sample_rate) ||
3719
                                    CHECK_CODEC(channels) ||
3720
                                    CHECK_CODEC(frame_size)) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3721
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3722
                                    matches = 0;
3723
                                }
3724
                            } else {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3725
                                http_log("Unknown codec type\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3726
                                matches = 0;
3727
                            }
3728
                        }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3729
                        if (!matches)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3730
                            break;
3731
                    }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3732
                } else
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3733
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3734
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3735
3736
                av_close_input_file(s);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3737
            } else
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3738
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3739
                        feed->feed_filename);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3740
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3741
            if (!matches) {
3742
                if (feed->readonly) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3743
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3744
                        feed->feed_filename);
3745
                    exit(1);
3746
                }
3747
                unlink(feed->feed_filename);
3748
            }
3749
        }
3750
        if (!url_exist(feed->feed_filename)) {
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3751
            AVFormatContext s1 = {0}, *s = &s1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3752
3753
            if (feed->readonly) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3754
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3755
                    feed->feed_filename);
3756
                exit(1);
3757
            }
3758
3759
            /* only write the header of the ffm file */
3760
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3761
                http_log("Could not open output feed file '%s'\n",
3762
                         feed->feed_filename);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3763
                exit(1);
3764
            }
3765
            s->oformat = feed->fmt;
3766
            s->nb_streams = feed->nb_streams;
3767
            for(i=0;i<s->nb_streams;i++) {
3768
                AVStream *st;
3769
                st = feed->streams[i];
3770
                s->streams[i] = st;
3771
            }
3772
            av_set_parameters(s, NULL);
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
3773
            if (av_write_header(s) < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3774
                http_log("Container doesn't supports the required parameters\n");
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
3775
                exit(1);
3776
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3777
            /* XXX: need better api */
3778
            av_freep(&s->priv_data);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3779
            url_fclose(s->pb);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3780
        }
3781
        /* get feed size and write index */
3782
        fd = open(feed->feed_filename, O_RDONLY);
3783
        if (fd < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3784
            http_log("Could not open output feed file '%s'\n",
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3785
                    feed->feed_filename);
3786
            exit(1);
3787
        }
3788
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3789
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3790
        feed->feed_size = lseek(fd, 0, SEEK_END);
3791
        /* ensure that we do not wrap before the end of file */
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3792
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3793
            feed->feed_max_size = feed->feed_size;
3794
3795
        close(fd);
3796
    }
3797
}
3798
3799
/* compute the bandwidth used by each stream */
3800
static void compute_bandwidth(void)
3801
{
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3802
    unsigned bandwidth;
3803
    int i;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3804
    FFStream *stream;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3805
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3806
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3807
        bandwidth = 0;
3808
        for(i=0;i<stream->nb_streams;i++) {
3809
            AVStream *st = stream->streams[i];
3810
            switch(st->codec->codec_type) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3811
            case AVMEDIA_TYPE_AUDIO:
3812
            case AVMEDIA_TYPE_VIDEO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3813
                bandwidth += st->codec->bit_rate;
3814
                break;
3815
            default:
3816
                break;
3817
            }
3818
        }
3819
        stream->bandwidth = (bandwidth + 999) / 1000;
3820
    }
3821
}
3822
3823
/* add a codec and set the default parameters */
3824
static void add_codec(FFStream *stream, AVCodecContext *av)
3825
{
3826
    AVStream *st;
3827
3828
    /* compute default parameters */
3829
    switch(av->codec_type) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3830
    case AVMEDIA_TYPE_AUDIO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3831
        if (av->bit_rate == 0)
3832
            av->bit_rate = 64000;
3833
        if (av->sample_rate == 0)
3834
            av->sample_rate = 22050;
3835
        if (av->channels == 0)
3836
            av->channels = 1;
3837
        break;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3838
    case AVMEDIA_TYPE_VIDEO:
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3839
        if (av->bit_rate == 0)
3840
            av->bit_rate = 64000;
3841
        if (av->time_base.num == 0){
3842
            av->time_base.den = 5;
3843
            av->time_base.num = 1;
3844
        }
3845
        if (av->width == 0 || av->height == 0) {
3846
            av->width = 160;
3847
            av->height = 128;
3848
        }
3849
        /* Bitrate tolerance is less for streaming */
3850
        if (av->bit_rate_tolerance == 0)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3851
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3852
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3853
        if (av->qmin == 0)
3854
            av->qmin = 3;
3855
        if (av->qmax == 0)
3856
            av->qmax = 31;
3857
        if (av->max_qdiff == 0)
3858
            av->max_qdiff = 3;
3859
        av->qcompress = 0.5;
3860
        av->qblur = 0.5;
3861
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3862
        if (!av->nsse_weight)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3863
            av->nsse_weight = 8;
3864
3865
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3866
        av->me_method = ME_EPZS;
3867
        av->rc_buffer_aggressivity = 1.0;
3868
3869
        if (!av->rc_eq)
3870
            av->rc_eq = "tex^qComp";
3871
        if (!av->i_quant_factor)
3872
            av->i_quant_factor = -0.8;
3873
        if (!av->b_quant_factor)
3874
            av->b_quant_factor = 1.25;
3875
        if (!av->b_quant_offset)
3876
            av->b_quant_offset = 1.25;
3877
        if (!av->rc_max_rate)
3878
            av->rc_max_rate = av->bit_rate * 2;
3879
3880
        if (av->rc_max_rate && !av->rc_buffer_size) {
3881
            av->rc_buffer_size = av->rc_max_rate;
3882
        }
3883
3884
3885
        break;
3886
    default:
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3887
        abort();
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3888
    }
3889
3890
    st = av_mallocz(sizeof(AVStream));
3891
    if (!st)
3892
        return;
3893
    st->codec = avcodec_alloc_context();
3894
    stream->streams[stream->nb_streams++] = st;
3895
    memcpy(st->codec, av, sizeof(AVCodecContext));
3896
}
3897
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3898
static enum CodecID opt_audio_codec(const char *arg)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3899
{
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3900
    AVCodec *p= avcodec_find_encoder_by_name(arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3901
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3902
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3903
        return CODEC_ID_NONE;
3904
3905
    return p->id;
3906
}
3907
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3908
static enum CodecID opt_video_codec(const char *arg)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3909
{
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
3910
    AVCodec *p= avcodec_find_encoder_by_name(arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3911
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3912
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3913
        return CODEC_ID_NONE;
3914
3915
    return p->id;
3916
}
3917
3918
/* simplistic plugin support */
3919
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3920
#if HAVE_DLOPEN
1.1.2 by Sebastian Dröge
Import upstream version 0.cvs20060823
3921
static void load_module(const char *filename)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3922
{
3923
    void *dll;
3924
    void (*init_func)(void);
3925
    dll = dlopen(filename, RTLD_NOW);
3926
    if (!dll) {
3927
        fprintf(stderr, "Could not load module '%s' - %s\n",
3928
                filename, dlerror());
3929
        return;
3930
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3931
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3932
    init_func = dlsym(dll, "ffserver_module_init");
3933
    if (!init_func) {
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
3934
        fprintf(stderr,
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3935
                "%s: init function 'ffserver_module_init()' not found\n",
3936
                filename);
3937
        dlclose(dll);
3938
    }
3939
3940
    init_func();
3941
}
3942
#endif
3943
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3944
static int ffserver_opt_default(const char *opt, const char *arg,
3945
                       AVCodecContext *avctx, int type)
3946
{
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3947
    int ret = 0;
3948
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3949
    if(o)
3950
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3951
    return ret;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
3952
}
3953
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3954
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3955
                                             const char *mime_type)
3956
{
3957
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3958
3959
    if (fmt) {
3960
        AVOutputFormat *stream_fmt;
3961
        char stream_format_name[64];
3962
3963
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3964
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3965
3966
        if (stream_fmt)
3967
            fmt = stream_fmt;
3968
    }
3969
3970
    return fmt;
3971
}
3972
3973
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3974
{
3975
    va_list vl;
3976
    va_start(vl, fmt);
3977
    fprintf(stderr, "%s:%d: ", filename, line_num);
3978
    vfprintf(stderr, fmt, vl);
3979
    va_end(vl);
3980
3981
    (*errors)++;
3982
}
3983
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3984
static int parse_ffconfig(const char *filename)
3985
{
3986
    FILE *f;
3987
    char line[1024];
3988
    char cmd[64];
3989
    char arg[1024];
3990
    const char *p;
3991
    int val, errors, line_num;
3992
    FFStream **last_stream, *stream, *redirect;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
3993
    FFStream **last_feed, *feed, *s;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3994
    AVCodecContext audio_enc, video_enc;
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
3995
    enum CodecID audio_id, video_id;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
3996
3997
    f = fopen(filename, "r");
3998
    if (!f) {
3999
        perror(filename);
4000
        return -1;
4001
    }
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4002
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4003
    errors = 0;
4004
    line_num = 0;
4005
    first_stream = NULL;
4006
    last_stream = &first_stream;
4007
    first_feed = NULL;
4008
    last_feed = &first_feed;
4009
    stream = NULL;
4010
    feed = NULL;
4011
    redirect = NULL;
4012
    audio_id = CODEC_ID_NONE;
4013
    video_id = CODEC_ID_NONE;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4014
4015
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4016
    for(;;) {
4017
        if (fgets(line, sizeof(line), f) == NULL)
4018
            break;
4019
        line_num++;
4020
        p = line;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4021
        while (isspace(*p))
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4022
            p++;
4023
        if (*p == '\0' || *p == '#')
4024
            continue;
4025
4026
        get_arg(cmd, sizeof(cmd), &p);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4027
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4028
        if (!strcasecmp(cmd, "Port")) {
4029
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4030
            val = atoi(arg);
4031
            if (val < 1 || val > 65536) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4032
                ERROR("Invalid_port: %s\n", arg);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4033
            }
4034
            my_http_addr.sin_port = htons(val);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4035
        } else if (!strcasecmp(cmd, "BindAddress")) {
4036
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4037
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4038
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4039
            }
4040
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4041
            ffserver_daemon = 0;
4042
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4043
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4044
            val = atoi(arg);
4045
            if (val < 1 || val > 65536) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4046
                ERROR("%s:%d: Invalid port: %s\n", arg);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4047
            }
4048
            my_rtsp_addr.sin_port = htons(atoi(arg));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4049
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4050
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4051
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4052
                ERROR("Invalid host/IP address: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4053
            }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4054
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4055
            get_arg(arg, sizeof(arg), &p);
4056
            val = atoi(arg);
4057
            if (val < 1 || val > 65536) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4058
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4059
            }
4060
            nb_max_http_connections = val;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4061
        } else if (!strcasecmp(cmd, "MaxClients")) {
4062
            get_arg(arg, sizeof(arg), &p);
4063
            val = atoi(arg);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4064
            if (val < 1 || val > nb_max_http_connections) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4065
                ERROR("Invalid MaxClients: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4066
            } else {
4067
                nb_max_connections = val;
4068
            }
4069
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4070
            int64_t llval;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4071
            get_arg(arg, sizeof(arg), &p);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4072
            llval = atoll(arg);
4073
            if (llval < 10 || llval > 10000000) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4074
                ERROR("Invalid MaxBandwidth: %s\n", arg);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4075
            } else
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4076
                max_bandwidth = llval;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4077
        } else if (!strcasecmp(cmd, "CustomLog")) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4078
            if (!ffserver_debug)
4079
                get_arg(logfilename, sizeof(logfilename), &p);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4080
        } else if (!strcasecmp(cmd, "<Feed")) {
4081
            /*********************************************/
4082
            /* Feed related options */
4083
            char *q;
4084
            if (stream || feed) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4085
                ERROR("Already in a tag\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4086
            } else {
4087
                feed = av_mallocz(sizeof(FFStream));
4088
                get_arg(feed->filename, sizeof(feed->filename), &p);
4089
                q = strrchr(feed->filename, '>');
4090
                if (*q)
4091
                    *q = '\0';
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4092
4093
                for (s = first_feed; s; s = s->next) {
4094
                    if (!strcmp(feed->filename, s->filename)) {
4095
                        ERROR("Feed '%s' already registered\n", s->filename);
4096
                    }
4097
                }
4098
4099
                feed->fmt = av_guess_format("ffm", NULL, NULL);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4100
                /* defaut feed file */
4101
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4102
                         "/tmp/%s.ffm", feed->filename);
4103
                feed->feed_max_size = 5 * 1024 * 1024;
4104
                feed->is_feed = 1;
4105
                feed->feed = feed; /* self feeding :-) */
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4106
4107
                /* add in stream list */
4108
                *last_stream = feed;
4109
                last_stream = &feed->next;
4110
                /* add in feed list */
4111
                *last_feed = feed;
4112
                last_feed = &feed->next_feed;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4113
            }
4114
        } else if (!strcasecmp(cmd, "Launch")) {
4115
            if (feed) {
4116
                int i;
4117
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4118
                feed->child_argv = av_mallocz(64 * sizeof(char *));
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4119
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4120
                for (i = 0; i < 62; i++) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4121
                    get_arg(arg, sizeof(arg), &p);
4122
                    if (!arg[0])
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4123
                        break;
4124
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4125
                    feed->child_argv[i] = av_strdup(arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4126
                }
4127
4128
                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4129
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4130
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4131
                    "http://%s:%d/%s",
4132
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4133
                    inet_ntoa(my_http_addr.sin_addr),
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4134
                    ntohs(my_http_addr.sin_port), feed->filename);
4135
            }
4136
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4137
            if (feed) {
4138
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4139
                feed->readonly = 1;
4140
            } else if (stream) {
4141
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4142
            }
4143
        } else if (!strcasecmp(cmd, "File")) {
4144
            if (feed) {
4145
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4146
            } else if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4147
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4148
        } else if (!strcasecmp(cmd, "Truncate")) {
4149
            if (feed) {
4150
                get_arg(arg, sizeof(arg), &p);
4151
                feed->truncate = strtod(arg, NULL);
4152
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4153
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4154
            if (feed) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4155
                char *p1;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4156
                double fsize;
4157
4158
                get_arg(arg, sizeof(arg), &p);
4159
                p1 = arg;
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4160
                fsize = strtod(p1, &p1);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4161
                switch(toupper(*p1)) {
4162
                case 'K':
4163
                    fsize *= 1024;
4164
                    break;
4165
                case 'M':
4166
                    fsize *= 1024 * 1024;
4167
                    break;
4168
                case 'G':
4169
                    fsize *= 1024 * 1024 * 1024;
4170
                    break;
4171
                }
4172
                feed->feed_max_size = (int64_t)fsize;
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4173
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4174
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4175
                }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4176
            }
4177
        } else if (!strcasecmp(cmd, "</Feed>")) {
4178
            if (!feed) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4179
                ERROR("No corresponding <Feed> for </Feed>\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4180
            }
4181
            feed = NULL;
4182
        } else if (!strcasecmp(cmd, "<Stream")) {
4183
            /*********************************************/
4184
            /* Stream related options */
4185
            char *q;
4186
            if (stream || feed) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4187
                ERROR("Already in a tag\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4188
            } else {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4189
                FFStream *s;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4190
                stream = av_mallocz(sizeof(FFStream));
4191
                get_arg(stream->filename, sizeof(stream->filename), &p);
4192
                q = strrchr(stream->filename, '>');
4193
                if (*q)
4194
                    *q = '\0';
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4195
4196
                for (s = first_stream; s; s = s->next) {
4197
                    if (!strcmp(stream->filename, s->filename)) {
4198
                        ERROR("Stream '%s' already registered\n", s->filename);
4199
                    }
4200
                }
4201
4202
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4203
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4204
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4205
                audio_id = CODEC_ID_NONE;
4206
                video_id = CODEC_ID_NONE;
4207
                if (stream->fmt) {
4208
                    audio_id = stream->fmt->audio_codec;
4209
                    video_id = stream->fmt->video_codec;
4210
                }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4211
4212
                *last_stream = stream;
4213
                last_stream = &stream->next;
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4214
            }
4215
        } else if (!strcasecmp(cmd, "Feed")) {
4216
            get_arg(arg, sizeof(arg), &p);
4217
            if (stream) {
4218
                FFStream *sfeed;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4219
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4220
                sfeed = first_feed;
4221
                while (sfeed != NULL) {
4222
                    if (!strcmp(sfeed->filename, arg))
4223
                        break;
4224
                    sfeed = sfeed->next_feed;
4225
                }
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4226
                if (!sfeed)
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4227
                    ERROR("feed '%s' not defined\n", arg);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4228
                else
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4229
                    stream->feed = sfeed;
4230
            }
4231
        } else if (!strcasecmp(cmd, "Format")) {
4232
            get_arg(arg, sizeof(arg), &p);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4233
            if (stream) {
4234
                if (!strcmp(arg, "status")) {
4235
                    stream->stream_type = STREAM_TYPE_STATUS;
4236
                    stream->fmt = NULL;
4237
                } else {
4238
                    stream->stream_type = STREAM_TYPE_LIVE;
4239
                    /* jpeg cannot be used here, so use single frame jpeg */
4240
                    if (!strcmp(arg, "jpeg"))
4241
                        strcpy(arg, "mjpeg");
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4242
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4243
                    if (!stream->fmt) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4244
                        ERROR("Unknown Format: %s\n", arg);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4245
                    }
4246
                }
4247
                if (stream->fmt) {
4248
                    audio_id = stream->fmt->audio_codec;
4249
                    video_id = stream->fmt->video_codec;
4250
                }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4251
            }
4252
        } else if (!strcasecmp(cmd, "InputFormat")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4253
            get_arg(arg, sizeof(arg), &p);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4254
            if (stream) {
4255
                stream->ifmt = av_find_input_format(arg);
4256
                if (!stream->ifmt) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4257
                    ERROR("Unknown input format: %s\n", arg);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4258
                }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4259
            }
4260
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4261
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4262
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4263
            } else {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4264
                ERROR("FaviconURL only permitted for status streams\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4265
            }
4266
        } else if (!strcasecmp(cmd, "Author")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4267
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4268
                get_arg(stream->author, sizeof(stream->author), &p);
4269
        } else if (!strcasecmp(cmd, "Comment")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4270
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4271
                get_arg(stream->comment, sizeof(stream->comment), &p);
4272
        } else if (!strcasecmp(cmd, "Copyright")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4273
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4274
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4275
        } else if (!strcasecmp(cmd, "Title")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4276
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4277
                get_arg(stream->title, sizeof(stream->title), &p);
4278
        } else if (!strcasecmp(cmd, "Preroll")) {
4279
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4280
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4281
                stream->prebuffer = atof(arg) * 1000;
4282
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4283
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4284
                stream->send_on_key = 1;
4285
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4286
            get_arg(arg, sizeof(arg), &p);
4287
            audio_id = opt_audio_codec(arg);
4288
            if (audio_id == CODEC_ID_NONE) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4289
                ERROR("Unknown AudioCodec: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4290
            }
4291
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4292
            get_arg(arg, sizeof(arg), &p);
4293
            video_id = opt_video_codec(arg);
4294
            if (video_id == CODEC_ID_NONE) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4295
                ERROR("Unknown VideoCodec: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4296
            }
4297
        } else if (!strcasecmp(cmd, "MaxTime")) {
4298
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4299
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4300
                stream->max_time = atof(arg) * 1000;
4301
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4302
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4303
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4304
                audio_enc.bit_rate = atoi(arg) * 1000;
4305
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4306
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4307
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4308
                audio_enc.channels = atoi(arg);
4309
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4310
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4311
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4312
                audio_enc.sample_rate = atoi(arg);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4313
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4314
            get_arg(arg, sizeof(arg), &p);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4315
            if (stream) {
4316
//                audio_enc.quality = atof(arg) * 1000;
4317
            }
4318
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4319
            if (stream) {
4320
                int minrate, maxrate;
4321
4322
                get_arg(arg, sizeof(arg), &p);
4323
4324
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4325
                    video_enc.rc_min_rate = minrate * 1000;
4326
                    video_enc.rc_max_rate = maxrate * 1000;
4327
                } else {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4328
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4329
                }
4330
            }
4331
        } else if (!strcasecmp(cmd, "Debug")) {
4332
            if (stream) {
4333
                get_arg(arg, sizeof(arg), &p);
4334
                video_enc.debug = strtol(arg,0,0);
4335
            }
4336
        } else if (!strcasecmp(cmd, "Strict")) {
4337
            if (stream) {
4338
                get_arg(arg, sizeof(arg), &p);
4339
                video_enc.strict_std_compliance = atoi(arg);
4340
            }
4341
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4342
            if (stream) {
4343
                get_arg(arg, sizeof(arg), &p);
4344
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4345
            }
4346
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4347
            if (stream) {
4348
                get_arg(arg, sizeof(arg), &p);
4349
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4350
            }
4351
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4352
            get_arg(arg, sizeof(arg), &p);
4353
            if (stream) {
4354
                video_enc.bit_rate = atoi(arg) * 1000;
4355
            }
4356
        } else if (!strcasecmp(cmd, "VideoSize")) {
4357
            get_arg(arg, sizeof(arg), &p);
4358
            if (stream) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4359
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4360
                if ((video_enc.width % 16) != 0 ||
4361
                    (video_enc.height % 16) != 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4362
                    ERROR("Image size must be a multiple of 16\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4363
                }
4364
            }
4365
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4366
            get_arg(arg, sizeof(arg), &p);
4367
            if (stream) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4368
                AVRational frame_rate;
4369
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4370
                    ERROR("Incorrect frame rate: %s\n", arg);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4371
                } else {
4372
                    video_enc.time_base.num = frame_rate.den;
4373
                    video_enc.time_base.den = frame_rate.num;
4374
                }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4375
            }
4376
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4377
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4378
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4379
                video_enc.gop_size = atoi(arg);
4380
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4381
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4382
                video_enc.gop_size = 1;
4383
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4384
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4385
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4386
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4387
            if (stream) {
4388
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4389
                video_enc.flags |= CODEC_FLAG_4MV;
4390
            }
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4391
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4392
                   !strcasecmp(cmd, "AVOptionAudio")) {
4393
            char arg2[1024];
4394
            AVCodecContext *avctx;
4395
            int type;
4396
            get_arg(arg, sizeof(arg), &p);
4397
            get_arg(arg2, sizeof(arg2), &p);
4398
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4399
                avctx = &video_enc;
4400
                type = AV_OPT_FLAG_VIDEO_PARAM;
4401
            } else {
4402
                avctx = &audio_enc;
4403
                type = AV_OPT_FLAG_AUDIO_PARAM;
4404
            }
4405
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4406
                ERROR("AVOption error: %s %s\n", arg, arg2);
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4407
            }
1.1.3 by Reinhard Tartler
Import upstream version 0.cvs20070307
4408
        } else if (!strcasecmp(cmd, "VideoTag")) {
4409
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4410
            if ((strlen(arg) == 4) && stream)
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4411
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4412
        } else if (!strcasecmp(cmd, "BitExact")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4413
            if (stream)
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4414
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4415
        } else if (!strcasecmp(cmd, "DctFastint")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4416
            if (stream)
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4417
                video_enc.dct_algo  = FF_DCT_FASTINT;
4418
        } else if (!strcasecmp(cmd, "IdctSimple")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4419
            if (stream)
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4420
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4421
        } else if (!strcasecmp(cmd, "Qscale")) {
4422
            get_arg(arg, sizeof(arg), &p);
4423
            if (stream) {
4424
                video_enc.flags |= CODEC_FLAG_QSCALE;
4425
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4426
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4427
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4428
            get_arg(arg, sizeof(arg), &p);
4429
            if (stream) {
4430
                video_enc.max_qdiff = atoi(arg);
4431
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4432
                    ERROR("VideoQDiff out of range\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4433
                }
4434
            }
4435
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4436
            get_arg(arg, sizeof(arg), &p);
4437
            if (stream) {
4438
                video_enc.qmax = atoi(arg);
4439
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4440
                    ERROR("VideoQMax out of range\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4441
                }
4442
            }
4443
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4444
            get_arg(arg, sizeof(arg), &p);
4445
            if (stream) {
4446
                video_enc.qmin = atoi(arg);
4447
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4448
                    ERROR("VideoQMin out of range\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4449
                }
4450
            }
4451
        } else if (!strcasecmp(cmd, "LumaElim")) {
4452
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4453
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4454
                video_enc.luma_elim_threshold = atoi(arg);
4455
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4456
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4457
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4458
                video_enc.chroma_elim_threshold = atoi(arg);
4459
        } else if (!strcasecmp(cmd, "LumiMask")) {
4460
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4461
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4462
                video_enc.lumi_masking = atof(arg);
4463
        } else if (!strcasecmp(cmd, "DarkMask")) {
4464
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4465
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4466
                video_enc.dark_masking = atof(arg);
4467
        } else if (!strcasecmp(cmd, "NoVideo")) {
4468
            video_id = CODEC_ID_NONE;
4469
        } else if (!strcasecmp(cmd, "NoAudio")) {
4470
            audio_id = CODEC_ID_NONE;
4471
        } else if (!strcasecmp(cmd, "ACL")) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4472
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4473
        } else if (!strcasecmp(cmd, "DynamicACL")) {
4474
            if (stream) {
4475
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4476
            }
4477
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4478
            get_arg(arg, sizeof(arg), &p);
4479
            if (stream) {
4480
                av_freep(&stream->rtsp_option);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4481
                stream->rtsp_option = av_strdup(arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4482
            }
4483
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4484
            get_arg(arg, sizeof(arg), &p);
4485
            if (stream) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4486
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4487
                    ERROR("Invalid host/IP address: %s\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4488
                }
4489
                stream->is_multicast = 1;
4490
                stream->loop = 1; /* default is looping */
4491
            }
4492
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4493
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4494
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4495
                stream->multicast_port = atoi(arg);
4496
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4497
            get_arg(arg, sizeof(arg), &p);
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4498
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4499
                stream->multicast_ttl = atoi(arg);
4500
        } else if (!strcasecmp(cmd, "NoLoop")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4501
            if (stream)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4502
                stream->loop = 0;
4503
        } else if (!strcasecmp(cmd, "</Stream>")) {
4504
            if (!stream) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4505
                ERROR("No corresponding <Stream> for </Stream>\n");
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4506
            } else {
4507
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4508
                    if (audio_id != CODEC_ID_NONE) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4509
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4510
                        audio_enc.codec_id = audio_id;
4511
                        add_codec(stream, &audio_enc);
4512
                    }
4513
                    if (video_id != CODEC_ID_NONE) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4514
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4515
                        video_enc.codec_id = video_id;
4516
                        add_codec(stream, &video_enc);
4517
                    }
4518
                }
4519
                stream = NULL;
4520
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4521
        } else if (!strcasecmp(cmd, "<Redirect")) {
4522
            /*********************************************/
4523
            char *q;
4524
            if (stream || feed || redirect) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4525
                ERROR("Already in a tag\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4526
            } else {
4527
                redirect = av_mallocz(sizeof(FFStream));
4528
                *last_stream = redirect;
4529
                last_stream = &redirect->next;
4530
4531
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4532
                q = strrchr(redirect->filename, '>');
4533
                if (*q)
4534
                    *q = '\0';
4535
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4536
            }
4537
        } else if (!strcasecmp(cmd, "URL")) {
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4538
            if (redirect)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4539
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4540
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4541
            if (!redirect) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4542
                ERROR("No corresponding <Redirect> for </Redirect>\n");
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4543
            } else {
4544
                if (!redirect->feed_filename[0]) {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4545
                    ERROR("No URL found for <Redirect>\n");
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4546
                }
4547
                redirect = NULL;
4548
            }
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4549
        } else if (!strcasecmp(cmd, "LoadModule")) {
4550
            get_arg(arg, sizeof(arg), &p);
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
4551
#if HAVE_DLOPEN
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4552
            load_module(arg);
4553
#else
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4554
            ERROR("Module support not compiled into this version: '%s'\n", arg);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4555
#endif
4556
        } else {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4557
            ERROR("Incorrect keyword: '%s'\n", cmd);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4558
        }
4559
    }
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4560
#undef ERROR
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4561
4562
    fclose(f);
4563
    if (errors)
4564
        return -1;
4565
    else
4566
        return 0;
4567
}
4568
4569
static void handle_child_exit(int sig)
4570
{
4571
    pid_t pid;
4572
    int status;
4573
4574
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4575
        FFStream *feed;
4576
4577
        for (feed = first_feed; feed; feed = feed->next) {
4578
            if (feed->pid == pid) {
4579
                int uptime = time(0) - feed->pid_start;
4580
4581
                feed->pid = 0;
4582
                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4583
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4584
                if (uptime < 30)
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4585
                    /* Turn off any more restarts */
4586
                    feed->child_argv = 0;
4587
            }
4588
        }
4589
    }
4590
4591
    need_to_start_children = 1;
4592
}
4593
1.1.7 by Reinhard Tartler
Import upstream version 0.svn20090204
4594
static void opt_debug(void)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4595
{
4596
    ffserver_debug = 1;
4597
    ffserver_daemon = 0;
4598
    logfilename[0] = '-';
4599
}
4600
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4601
static void show_help(void)
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4602
{
1.1.6 by Reinhard Tartler
Import upstream version 0.svn20090119
4603
    printf("usage: ffserver [options]\n"
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4604
           "Hyper fast multi format Audio/Video streaming server\n");
4605
    printf("\n");
4606
    show_help_options(options, "Main options:\n", 0, 0);
4607
}
4608
4609
static const OptionDef options[] = {
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4610
#include "cmdutils_common_opts.h"
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4611
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4612
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4613
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4614
    { NULL },
4615
};
4616
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4617
int main(int argc, char **argv)
4618
{
4619
    struct sigaction sigact;
4620
4621
    av_register_all();
4622
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4623
    show_banner();
1.1.4 by Reinhard Tartler
Import upstream version 0.svn20080206
4624
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4625
    my_program_name = argv[0];
4626
    my_program_dir = getcwd(0, 0);
4627
    ffserver_daemon = 1;
1.1.1 by Sebastian Dröge
Import upstream version 0.cvs20060329
4628
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4629
    parse_options(argc, argv, options, NULL);
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4630
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4631
    unsetenv("http_proxy");             /* Kill the http_proxy */
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4632
0.3.1 by Reinhard Tartler
Import upstream version 0.6~svn20100505
4633
    av_lfg_init(&random_state, ff_random_get_seed());
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4634
4635
    memset(&sigact, 0, sizeof(sigact));
4636
    sigact.sa_handler = handle_child_exit;
4637
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4638
    sigaction(SIGCHLD, &sigact, 0);
4639
4640
    if (parse_ffconfig(config_filename) < 0) {
4641
        fprintf(stderr, "Incorrect config file - exiting.\n");
4642
        exit(1);
4643
    }
4644
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4645
    /* open log file if needed */
4646
    if (logfilename[0] != '\0') {
4647
        if (!strcmp(logfilename, "-"))
4648
            logfile = stdout;
4649
        else
4650
            logfile = fopen(logfilename, "a");
4651
        av_log_set_callback(http_av_log);
4652
    }
4653
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4654
    build_file_streams();
4655
4656
    build_feed_streams();
4657
4658
    compute_bandwidth();
4659
4660
    /* put the process in background and detach it from its TTY */
4661
    if (ffserver_daemon) {
4662
        int pid;
4663
4664
        pid = fork();
4665
        if (pid < 0) {
4666
            perror("fork");
4667
            exit(1);
4668
        } else if (pid > 0) {
4669
            /* parent : exit */
4670
            exit(0);
4671
        } else {
4672
            /* child */
4673
            setsid();
4674
            close(0);
4675
            open("/dev/null", O_RDWR);
4676
            if (strcmp(logfilename, "-") != 0) {
4677
                close(1);
4678
                dup(0);
4679
            }
4680
            close(2);
4681
            dup(0);
4682
        }
4683
    }
4684
4685
    /* signal init */
4686
    signal(SIGPIPE, SIG_IGN);
4687
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4688
    if (ffserver_daemon)
4689
        chdir("/");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4690
4691
    if (http_server() < 0) {
1.1.5 by Reinhard Tartler
Import upstream version 0.svn20081115
4692
        http_log("Could not start server\n");
1 by Daniel T Chen
Import upstream version 0.cvs20050918
4693
        exit(1);
4694
    }
4695
4696
    return 0;
4697
}