Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 9c6b3b97

History | View | Annotate | Download (153 KB)

1 85f07f22 Fabrice Bellard
/*
2
 * Multiple format streaming server
3 773a21b8 Fabrice Bellard
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 85f07f22 Fabrice Bellard
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 773a21b8 Fabrice Bellard
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 85f07f22 Fabrice Bellard
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 85f07f22 Fabrice Bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 773a21b8 Fabrice Bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16 85f07f22 Fabrice Bellard
 *
17 773a21b8 Fabrice Bellard
 * You should have received a copy of the GNU Lesser General Public
18 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 85f07f22 Fabrice Bellard
 */
21 364a9607 Diego Biurrun
22 29d3ed3b Aurelien Jacobs
#define _XOPEN_SOURCE 600
23
24 0f4e8165 Ronald S. Bultje
#include "config.h"
25 b250f9c6 Aurelien Jacobs
#if !HAVE_CLOSESOCKET
26 0f4e8165 Ronald S. Bultje
#define closesocket close
27
#endif
28
#include <string.h>
29 ea452b54 Aurelien Jacobs
#include <strings.h>
30 0f4e8165 Ronald S. Bultje
#include <stdlib.h>
31 245976da Diego Biurrun
#include "libavformat/avformat.h"
32
#include "libavformat/network.h"
33
#include "libavformat/os_support.h"
34 302879cb Luca Abeni
#include "libavformat/rtpdec.h"
35 245976da Diego Biurrun
#include "libavformat/rtsp.h"
36 959da985 Stefano Sabatini
#include "libavutil/avstring.h"
37 042819c5 Baptiste Coudurier
#include "libavutil/lfg.h"
38
#include "libavutil/random_seed.h"
39 7ab08864 Baptiste Coudurier
#include "libavcodec/opt.h"
40 85f07f22 Fabrice Bellard
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
44 b250f9c6 Aurelien Jacobs
#if HAVE_POLL_H
45 f8cda19e Luca Abeni
#include <poll.h>
46 b0c858d8 François Revol
#endif
47 85f07f22 Fabrice Bellard
#include <errno.h>
48
#include <sys/time.h>
49
#include <time.h>
50 5eb765ef Philip Gladstone
#include <sys/wait.h>
51 85f07f22 Fabrice Bellard
#include <signal.h>
52 b250f9c6 Aurelien Jacobs
#if HAVE_DLFCN_H
53 2effd274 Fabrice Bellard
#include <dlfcn.h>
54 6638d424 Philip Gladstone
#endif
55 2effd274 Fabrice Bellard
56 4ce5df08 Stefano Sabatini
#include "cmdutils.h"
57 85f07f22 Fabrice Bellard
58 64555bd9 Michael Niedermayer
const char program_name[] = "FFserver";
59 ea9c581f Stefano Sabatini
const int program_birth_year = 2000;
60 86074ed1 Stefano Sabatini
61 5a635bc7 Stefano Sabatini
static const OptionDef options[];
62
63 85f07f22 Fabrice Bellard
enum HTTPState {
64
    HTTPSTATE_WAIT_REQUEST,
65
    HTTPSTATE_SEND_HEADER,
66
    HTTPSTATE_SEND_DATA_HEADER,
67 2effd274 Fabrice Bellard
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
68 85f07f22 Fabrice Bellard
    HTTPSTATE_SEND_DATA_TRAILER,
69 115329f1 Diego Biurrun
    HTTPSTATE_RECEIVE_DATA,
70 2effd274 Fabrice Bellard
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
71
    HTTPSTATE_READY,
72
73
    RTSPSTATE_WAIT_REQUEST,
74
    RTSPSTATE_SEND_REPLY,
75 bc351386 Fabrice Bellard
    RTSPSTATE_SEND_PACKET,
76 85f07f22 Fabrice Bellard
};
77
78 9507a12e Baptiste Coudurier
static const char *http_state[] = {
79 2effd274 Fabrice Bellard
    "HTTP_WAIT_REQUEST",
80
    "HTTP_SEND_HEADER",
81
82 85f07f22 Fabrice Bellard
    "SEND_DATA_HEADER",
83
    "SEND_DATA",
84
    "SEND_DATA_TRAILER",
85
    "RECEIVE_DATA",
86
    "WAIT_FEED",
87 2effd274 Fabrice Bellard
    "READY",
88
89
    "RTSP_WAIT_REQUEST",
90
    "RTSP_SEND_REPLY",
91 bc351386 Fabrice Bellard
    "RTSP_SEND_PACKET",
92 85f07f22 Fabrice Bellard
};
93
94 cde25790 Philip Gladstone
#define IOBUFFER_INIT_SIZE 8192
95 85f07f22 Fabrice Bellard
96
/* timeouts are in ms */
97 2effd274 Fabrice Bellard
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
98
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
99
100 85f07f22 Fabrice Bellard
#define SYNC_TIMEOUT (10 * 1000)
101
102 b516ecdd Ronald S. Bultje
typedef struct RTSPActionServerSetup {
103
    uint32_t ipaddr;
104
    char transport_option[512];
105
} RTSPActionServerSetup;
106
107 5eb765ef Philip Gladstone
typedef struct {
108 0c1a9eda Zdenek Kabelac
    int64_t count1, count2;
109 c3f58185 Alex Beregszaszi
    int64_t time1, time2;
110 5eb765ef Philip Gladstone
} DataRateData;
111
112 85f07f22 Fabrice Bellard
/* 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 */
118 c3f58185 Alex Beregszaszi
    int64_t timeout;
119 0c1a9eda Zdenek Kabelac
    uint8_t *buffer_ptr, *buffer_end;
120 85f07f22 Fabrice Bellard
    int http_error;
121 edfdd798 Alex Beregszaszi
    int post;
122 19c8c4ec Ronald S. Bultje
    int chunked_encoding;
123
    int chunk_size;               /* 0 if it needs to be read */
124 85f07f22 Fabrice Bellard
    struct HTTPContext *next;
125 42a63c6a Philip Gladstone
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
126 0c1a9eda Zdenek Kabelac
    int64_t data_count;
127 85f07f22 Fabrice Bellard
    /* feed input */
128
    int feed_fd;
129
    /* input format handling */
130
    AVFormatContext *fmt_in;
131 c3f58185 Alex Beregszaszi
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
132 0c1a9eda Zdenek Kabelac
    int64_t first_pts;            /* initial pts value */
133 e240a0bb Fabrice Bellard
    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 85f07f22 Fabrice Bellard
    /* output format handling */
141
    struct FFStream *stream;
142 cde25790 Philip Gladstone
    /* -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 2effd274 Fabrice Bellard
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
147 85f07f22 Fabrice Bellard
    int last_packet_sent; /* true if last data packet was sent */
148 7434ba6d Philip Gladstone
    int suppress_log;
149 5eb765ef Philip Gladstone
    DataRateData datarate;
150 3120d2a2 Philip Gladstone
    int wmp_client_id;
151 7434ba6d Philip Gladstone
    char protocol[16];
152
    char method[16];
153
    char url[128];
154 cde25790 Philip Gladstone
    int buffer_size;
155 0c1a9eda Zdenek Kabelac
    uint8_t *buffer;
156 2effd274 Fabrice Bellard
    int is_packetized; /* if true, the stream is packetized */
157
    int packet_stream_index; /* current stream for output in state machine */
158 115329f1 Diego Biurrun
159 2effd274 Fabrice Bellard
    /* RTSP state specific */
160 0c1a9eda Zdenek Kabelac
    uint8_t *pb_buffer; /* XXX: use that in all the code */
161 2effd274 Fabrice Bellard
    ByteIOContext *pb;
162
    int seq; /* RTSP sequence number */
163 115329f1 Diego Biurrun
164 2effd274 Fabrice Bellard
    /* RTP state specific */
165 90abbdba Ronald S. Bultje
    enum RTSPLowerTransport rtp_protocol;
166 2effd274 Fabrice Bellard
    char session_id[32]; /* session id */
167
    AVFormatContext *rtp_ctx[MAX_STREAMS];
168 e240a0bb Fabrice Bellard
169 bc351386 Fabrice Bellard
    /* 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 85f07f22 Fabrice Bellard
} HTTPContext;
176
177
/* each generated stream is described here */
178
enum StreamType {
179
    STREAM_TYPE_LIVE,
180
    STREAM_TYPE_STATUS,
181 cde25790 Philip Gladstone
    STREAM_TYPE_REDIRECT,
182 85f07f22 Fabrice Bellard
};
183
184 8256c0a3 Philip Gladstone
enum IPAddressAction {
185
    IP_ALLOW = 1,
186
    IP_DENY,
187
};
188
189
typedef struct IPAddressACL {
190
    struct IPAddressACL *next;
191
    enum IPAddressAction action;
192 efa04ce2 Philip Gladstone
    /* These are in host order */
193 8256c0a3 Philip Gladstone
    struct in_addr first;
194
    struct in_addr last;
195
} IPAddressACL;
196
197 85f07f22 Fabrice Bellard
/* 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 2effd274 Fabrice Bellard
    struct FFStream *feed;   /* feed we are using (can be null if
202
                                coming from file) */
203 e240a0bb Fabrice Bellard
    AVFormatParameters *ap_in; /* input parameters */
204
    AVInputFormat *ifmt;       /* if non NULL, force input format */
205 bd7cf6ad Fabrice Bellard
    AVOutputFormat *fmt;
206 8256c0a3 Philip Gladstone
    IPAddressACL *acl;
207 58f48adb Benjamin Larsson
    char dynamic_acl[1024];
208 85f07f22 Fabrice Bellard
    int nb_streams;
209 42a63c6a Philip Gladstone
    int prebuffer;      /* Number of millseconds early to start */
210 c3f58185 Alex Beregszaszi
    int64_t max_time;      /* Number of milliseconds to run */
211 79c4ea3c Philip Gladstone
    int send_on_key;
212 85f07f22 Fabrice Bellard
    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 2ac887ba Philip Gladstone
    char author[512];
217
    char title[512];
218
    char copyright[512];
219
    char comment[512];
220 cde25790 Philip Gladstone
    pid_t pid;  /* Of ffmpeg process */
221 5eb765ef Philip Gladstone
    time_t pid_start;  /* Of ffmpeg process */
222 cde25790 Philip Gladstone
    char **child_argv;
223 85f07f22 Fabrice Bellard
    struct FFStream *next;
224 177d2564 Baptiste Coudurier
    unsigned bandwidth; /* bandwidth, in kbits/s */
225 2effd274 Fabrice Bellard
    /* RTSP options */
226
    char *rtsp_option;
227 829ac53d Fabrice Bellard
    /* multicast specific */
228
    int is_multicast;
229
    struct in_addr multicast_ip;
230
    int multicast_port; /* first port used for multicast */
231 6edd6884 Fabrice Bellard
    int multicast_ttl;
232
    int loop; /* if true, send the stream in loops (only meaningful if file) */
233 829ac53d Fabrice Bellard
234 85f07f22 Fabrice Bellard
    /* feed specific */
235 2effd274 Fabrice Bellard
    int feed_opened;     /* true if someone is writing to the feed */
236 85f07f22 Fabrice Bellard
    int is_feed;         /* true if it is a feed */
237 e322ea48 Philip Gladstone
    int readonly;        /* True if writing is prohibited to the file */
238 861ec13a Baptiste Coudurier
    int truncate;        /* True if feeder connection truncate the feed file */
239 a6e14edd Philip Gladstone
    int conns_served;
240 0c1a9eda Zdenek Kabelac
    int64_t bytes_served;
241 6b0bdc75 Alex Beregszaszi
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
242 8bfb108b Diego Biurrun
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
243 0c1a9eda Zdenek Kabelac
    int64_t feed_size;          /* current size of feed */
244 85f07f22 Fabrice Bellard
    struct FFStream *next_feed;
245
} FFStream;
246
247
typedef struct FeedData {
248
    long long data_count;
249 8bfb108b Diego Biurrun
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
250 85f07f22 Fabrice Bellard
} FeedData;
251
252 18405874 Alex Beregszaszi
static struct sockaddr_in my_http_addr;
253
static struct sockaddr_in my_rtsp_addr;
254 2effd274 Fabrice Bellard
255 33f5e2ec Alex Beregszaszi
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 */
259 85f07f22 Fabrice Bellard
260 2effd274 Fabrice Bellard
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 85f07f22 Fabrice Bellard
static int http_parse_request(HTTPContext *c);
266 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c);
267 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c);
268 85f07f22 Fabrice Bellard
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 2effd274 Fabrice Bellard
272
/* RTSP handling */
273
static int rtsp_parse_request(HTTPContext *c);
274
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
275 0df65975 Andriy Rysin
static void rtsp_cmd_options(HTTPContext *c, const char *url);
276 a9e534d5 Ronald S. Bultje
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);
280 2effd274 Fabrice Bellard
281 829ac53d Fabrice Bellard
/* SDP handling */
282 115329f1 Diego Biurrun
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
283 829ac53d Fabrice Bellard
                                   struct in_addr my_ip);
284
285 2effd274 Fabrice Bellard
/* RTP handling */
286 115329f1 Diego Biurrun
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
287 bc351386 Fabrice Bellard
                                       FFStream *stream, const char *session_id,
288 90abbdba Ronald S. Bultje
                                       enum RTSPLowerTransport rtp_protocol);
289 115329f1 Diego Biurrun
static int rtp_new_av_stream(HTTPContext *c,
290 bc351386 Fabrice Bellard
                             int stream_index, struct sockaddr_in *dest_addr,
291
                             HTTPContext *rtsp_c);
292 85f07f22 Fabrice Bellard
293 cde25790 Philip Gladstone
static const char *my_program_name;
294 d6562d2c Philip Gladstone
static const char *my_program_dir;
295 cde25790 Philip Gladstone
296 6675a5bf Stefano Sabatini
static const char *config_filename = "/etc/ffserver.conf";
297
298 2ac887ba Philip Gladstone
static int ffserver_debug;
299 2effd274 Fabrice Bellard
static int ffserver_daemon;
300 2ac887ba Philip Gladstone
static int no_launch;
301 5eb765ef Philip Gladstone
static int need_to_start_children;
302 2ac887ba Philip Gladstone
303 1c9ff179 Stefano Sabatini
/* maximum number of simultaneous HTTP connections */
304
static unsigned int nb_max_http_connections = 2000;
305 4af92de6 Stefano Sabatini
static unsigned int nb_max_connections = 5;
306
static unsigned int nb_connections;
307 85f07f22 Fabrice Bellard
308 f69bb0cc Baptiste Coudurier
static uint64_t max_bandwidth = 1000;
309 1ad8289e Baptiste Coudurier
static uint64_t current_bandwidth;
310 42a63c6a Philip Gladstone
311 c3f58185 Alex Beregszaszi
static int64_t cur_time;           // Making this global saves on passing it around everywhere
312 5eb765ef Philip Gladstone
313 042819c5 Baptiste Coudurier
static AVLFG random_state;
314 1df93ae9 Alex Beregszaszi
315 85f07f22 Fabrice Bellard
static FILE *logfile = NULL;
316
317 22f73dcc Måns Rullgård
/* 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
353 9fd3442f Baptiste Coudurier
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 bcd3ce59 Baptiste Coudurier
static void http_vlog(const char *fmt, va_list vargs)
368 85f07f22 Fabrice Bellard
{
369 124ed1c0 Baptiste Coudurier
    static int print_prefix = 1;
370 7434ba6d Philip Gladstone
    if (logfile) {
371 124ed1c0 Baptiste Coudurier
        if (print_prefix) {
372 9fd3442f Baptiste Coudurier
            char buf[32];
373
            ctime1(buf);
374
            fprintf(logfile, "%s ", buf);
375 124ed1c0 Baptiste Coudurier
        }
376
        print_prefix = strstr(fmt, "\n") != NULL;
377 bcd3ce59 Baptiste Coudurier
        vfprintf(logfile, fmt, vargs);
378 7434ba6d Philip Gladstone
        fflush(logfile);
379
    }
380 bcd3ce59 Baptiste Coudurier
}
381
382 7f6a384a Diego Biurrun
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
383 bcd3ce59 Baptiste Coudurier
{
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;
394 49ceb58b Michael Niedermayer
    if (level > av_log_get_level())
395 bcd3ce59 Baptiste Coudurier
        return;
396
    if (print_prefix && avc)
397 59e7894c Baptiste Coudurier
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
398 bcd3ce59 Baptiste Coudurier
    print_prefix = strstr(fmt, "\n") != NULL;
399
    http_vlog(fmt, vargs);
400 85f07f22 Fabrice Bellard
}
401
402 6edd6884 Fabrice Bellard
static void log_connection(HTTPContext *c)
403
{
404 115329f1 Diego Biurrun
    if (c->suppress_log)
405 6edd6884 Fabrice Bellard
        return;
406
407 82e0be62 Baptiste Coudurier
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
408
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
409 6edd6884 Fabrice Bellard
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
410 cde25790 Philip Gladstone
}
411
412 0c1a9eda Zdenek Kabelac
static void update_datarate(DataRateData *drd, int64_t count)
413 5eb765ef Philip Gladstone
{
414
    if (!drd->time1 && !drd->count1) {
415
        drd->time1 = drd->time2 = cur_time;
416
        drd->count1 = drd->count2 = count;
417 eeffbdea Alex Beregszaszi
    } else if (cur_time - drd->time2 > 5000) {
418 33a4ecbe Alex Beregszaszi
        drd->time1 = drd->time2;
419
        drd->count1 = drd->count2;
420
        drd->time2 = cur_time;
421
        drd->count2 = count;
422 5eb765ef Philip Gladstone
    }
423
}
424
425
/* In bytes per second */
426 0c1a9eda Zdenek Kabelac
static int compute_datarate(DataRateData *drd, int64_t count)
427 5eb765ef Philip Gladstone
{
428
    if (cur_time == drd->time1)
429
        return 0;
430 115329f1 Diego Biurrun
431 5eb765ef Philip Gladstone
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
432
}
433
434 a782f209 Philip Gladstone
435 cde25790 Philip Gladstone
static void start_children(FFStream *feed)
436
{
437 2ac887ba Philip Gladstone
    if (no_launch)
438
        return;
439
440 cde25790 Philip Gladstone
    for (; feed; feed = feed->next) {
441 5eb765ef Philip Gladstone
        if (feed->child_argv && !feed->pid) {
442
            feed->pid_start = time(0);
443
444 cde25790 Philip Gladstone
            feed->pid = fork();
445
446
            if (feed->pid < 0) {
447 b4befb99 Baptiste Coudurier
                http_log("Unable to create children\n");
448 cde25790 Philip Gladstone
                exit(1);
449
            }
450
            if (!feed->pid) {
451
                /* In child */
452
                char pathname[1024];
453
                char *slash;
454
                int i;
455
456 40444a59 Stefano Sabatini
                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 8bf61f5b Stefano Sabatini
                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 40444a59 Stefano Sabatini
471 611c5741 Alex Beregszaszi
                for (i = 3; i < 256; i++)
472 5eb765ef Philip Gladstone
                    close(i);
473 cde25790 Philip Gladstone
474 5eb765ef Philip Gladstone
                if (!ffserver_debug) {
475 2ac887ba Philip Gladstone
                    i = open("/dev/null", O_RDWR);
476 3296409d Baptiste Coudurier
                    if (i != -1) {
477 2ac887ba Philip Gladstone
                        dup2(i, 0);
478 3296409d Baptiste Coudurier
                        dup2(i, 1);
479
                        dup2(i, 2);
480 5eb765ef Philip Gladstone
                        close(i);
481 3296409d Baptiste Coudurier
                    }
482 2ac887ba Philip Gladstone
                }
483 cde25790 Philip Gladstone
484 d6562d2c Philip Gladstone
                /* This is needed to make relative pathnames work */
485
                chdir(my_program_dir);
486
487 a4d70941 Philip Gladstone
                signal(SIGPIPE, SIG_DFL);
488
489 cde25790 Philip Gladstone
                execvp(pathname, feed->child_argv);
490
491
                _exit(1);
492
            }
493
        }
494
    }
495 7434ba6d Philip Gladstone
}
496
497 2effd274 Fabrice Bellard
/* open a listening socket */
498
static int socket_open_listen(struct sockaddr_in *my_addr)
499 85f07f22 Fabrice Bellard
{
500 2effd274 Fabrice Bellard
    int server_fd, tmp;
501 85f07f22 Fabrice Bellard
502
    server_fd = socket(AF_INET,SOCK_STREAM,0);
503
    if (server_fd < 0) {
504
        perror ("socket");
505
        return -1;
506
    }
507 115329f1 Diego Biurrun
508 85f07f22 Fabrice Bellard
    tmp = 1;
509
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
510
511 2effd274 Fabrice Bellard
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
512 b17d099d Philip Gladstone
        char bindmsg[32];
513
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
514
        perror (bindmsg);
515 d96633bb Alex Beregszaszi
        closesocket(server_fd);
516 85f07f22 Fabrice Bellard
        return -1;
517
    }
518 115329f1 Diego Biurrun
519 85f07f22 Fabrice Bellard
    if (listen (server_fd, 5) < 0) {
520
        perror ("listen");
521 d96633bb Alex Beregszaszi
        closesocket(server_fd);
522 85f07f22 Fabrice Bellard
        return -1;
523
    }
524 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(server_fd, 1);
525 2effd274 Fabrice Bellard
526
    return server_fd;
527
}
528
529 6edd6884 Fabrice Bellard
/* 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 */
542 1df93ae9 Alex Beregszaszi
            snprintf(session_id, sizeof(session_id), "%08x%08x",
543 042819c5 Baptiste Coudurier
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
544 6edd6884 Fabrice Bellard
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
555 115329f1 Diego Biurrun
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
556 90abbdba Ronald S. Bultje
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
557 611c5741 Alex Beregszaszi
            if (!rtp_c)
558 6edd6884 Fabrice Bellard
                continue;
559 611c5741 Alex Beregszaszi
560 6edd6884 Fabrice Bellard
            if (open_input_stream(rtp_c, "") < 0) {
561 b4befb99 Baptiste Coudurier
                http_log("Could not open input stream for stream '%s'\n",
562
                         stream->filename);
563 6edd6884 Fabrice Bellard
                continue;
564
            }
565
566
            /* open each RTP stream */
567 115329f1 Diego Biurrun
            for(stream_index = 0; stream_index < stream->nb_streams;
568 6edd6884 Fabrice Bellard
                stream_index++) {
569 115329f1 Diego Biurrun
                dest_addr.sin_port = htons(stream->multicast_port +
570 6edd6884 Fabrice Bellard
                                           2 * stream_index);
571 bc351386 Fabrice Bellard
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
572 b4befb99 Baptiste Coudurier
                    http_log("Could not open output stream '%s/streamid=%d'\n",
573
                             stream->filename, stream_index);
574 0fa45e19 Fabrice Bellard
                    exit(1);
575 6edd6884 Fabrice Bellard
                }
576
            }
577
578
            /* change state to send data */
579
            rtp_c->state = HTTPSTATE_SEND_DATA;
580
        }
581
    }
582
}
583 2effd274 Fabrice Bellard
584
/* main loop of the http server */
585
static int http_server(void)
586
{
587 d2a1ea1d Baptiste Coudurier
    int server_fd = 0, rtsp_server_fd = 0;
588
    int ret, delay, delay1;
589 1c9ff179 Stefano Sabatini
    struct pollfd *poll_table, *poll_entry;
590 2effd274 Fabrice Bellard
    HTTPContext *c, *c_next;
591
592 a7f361eb Baptiste Coudurier
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
593 1c9ff179 Stefano Sabatini
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
594
        return -1;
595
    }
596
597 d2a1ea1d Baptiste Coudurier
    if (my_http_addr.sin_port) {
598 2b9cd1e7 Baptiste Coudurier
        server_fd = socket_open_listen(&my_http_addr);
599
        if (server_fd < 0)
600
            return -1;
601 d2a1ea1d Baptiste Coudurier
    }
602 85f07f22 Fabrice Bellard
603 d2a1ea1d Baptiste Coudurier
    if (my_rtsp_addr.sin_port) {
604 2b9cd1e7 Baptiste Coudurier
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
605
        if (rtsp_server_fd < 0)
606
            return -1;
607 d2a1ea1d Baptiste Coudurier
    }
608
609
    if (!rtsp_server_fd && !server_fd) {
610
        http_log("HTTP and RTSP disabled.\n");
611
        return -1;
612
    }
613 115329f1 Diego Biurrun
614 a3341b9d Baptiste Coudurier
    http_log("FFserver started.\n");
615 85f07f22 Fabrice Bellard
616 cde25790 Philip Gladstone
    start_children(first_feed);
617
618 6edd6884 Fabrice Bellard
    start_multicast();
619
620 85f07f22 Fabrice Bellard
    for(;;) {
621
        poll_entry = poll_table;
622 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
623 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = server_fd;
624
            poll_entry->events = POLLIN;
625
            poll_entry++;
626 d2a1ea1d Baptiste Coudurier
        }
627
        if (rtsp_server_fd) {
628 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = rtsp_server_fd;
629
            poll_entry->events = POLLIN;
630
            poll_entry++;
631 d2a1ea1d Baptiste Coudurier
        }
632 2effd274 Fabrice Bellard
633 85f07f22 Fabrice Bellard
        /* wait for events on each HTTP handle */
634
        c = first_http_ctx;
635 2effd274 Fabrice Bellard
        delay = 1000;
636 85f07f22 Fabrice Bellard
        while (c != NULL) {
637
            int fd;
638
            fd = c->fd;
639
            switch(c->state) {
640 2effd274 Fabrice Bellard
            case HTTPSTATE_SEND_HEADER:
641
            case RTSPSTATE_SEND_REPLY:
642 bc351386 Fabrice Bellard
            case RTSPSTATE_SEND_PACKET:
643 85f07f22 Fabrice Bellard
                c->poll_entry = poll_entry;
644
                poll_entry->fd = fd;
645 2effd274 Fabrice Bellard
                poll_entry->events = POLLOUT;
646 85f07f22 Fabrice Bellard
                poll_entry++;
647
                break;
648
            case HTTPSTATE_SEND_DATA_HEADER:
649
            case HTTPSTATE_SEND_DATA:
650
            case HTTPSTATE_SEND_DATA_TRAILER:
651 2effd274 Fabrice Bellard
                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 e240a0bb Fabrice Bellard
                    /* 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 2effd274 Fabrice Bellard
                }
665 85f07f22 Fabrice Bellard
                break;
666 2effd274 Fabrice Bellard
            case HTTPSTATE_WAIT_REQUEST:
667 85f07f22 Fabrice Bellard
            case HTTPSTATE_RECEIVE_DATA:
668
            case HTTPSTATE_WAIT_FEED:
669 2effd274 Fabrice Bellard
            case RTSPSTATE_WAIT_REQUEST:
670 85f07f22 Fabrice Bellard
                /* need to catch errors */
671
                c->poll_entry = poll_entry;
672
                poll_entry->fd = fd;
673 a6e14edd Philip Gladstone
                poll_entry->events = POLLIN;/* Maybe this will work */
674 85f07f22 Fabrice Bellard
                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 2effd274 Fabrice Bellard
            ret = poll(poll_table, poll_entry - poll_table, delay);
687 8da4034f Alex Beregszaszi
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
688
                ff_neterrno() != FF_NETERROR(EINTR))
689 53e2f9ca Michael Niedermayer
                return -1;
690 e8d658df Luca Abeni
        } while (ret < 0);
691 115329f1 Diego Biurrun
692 c3f58185 Alex Beregszaszi
        cur_time = av_gettime() / 1000;
693 85f07f22 Fabrice Bellard
694 5eb765ef Philip Gladstone
        if (need_to_start_children) {
695
            need_to_start_children = 0;
696
            start_children(first_feed);
697
        }
698
699 85f07f22 Fabrice Bellard
        /* now handle the events */
700 2effd274 Fabrice Bellard
        for(c = first_http_ctx; c != NULL; c = c_next) {
701
            c_next = c->next;
702
            if (handle_connection(c) < 0) {
703 85f07f22 Fabrice Bellard
                /* close and free the connection */
704 7434ba6d Philip Gladstone
                log_connection(c);
705 2effd274 Fabrice Bellard
                close_connection(c);
706 85f07f22 Fabrice Bellard
            }
707
        }
708
709
        poll_entry = poll_table;
710 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
711 2b9cd1e7 Baptiste Coudurier
            /* new HTTP connection request ? */
712
            if (poll_entry->revents & POLLIN)
713
                new_connection(server_fd, 0);
714
            poll_entry++;
715 d2a1ea1d Baptiste Coudurier
        }
716
        if (rtsp_server_fd) {
717 2b9cd1e7 Baptiste Coudurier
            /* new RTSP connection request ? */
718
            if (poll_entry->revents & POLLIN)
719
                new_connection(rtsp_server_fd, 1);
720 d2a1ea1d Baptiste Coudurier
        }
721 85f07f22 Fabrice Bellard
    }
722
}
723
724 2effd274 Fabrice Bellard
/* start waiting for a new HTTP/RTSP request */
725
static void start_wait_request(HTTPContext *c, int is_rtsp)
726 85f07f22 Fabrice Bellard
{
727 2effd274 Fabrice Bellard
    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
739 0bdd8b85 Baptiste Coudurier
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
755 2effd274 Fabrice Bellard
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);
762 115329f1 Diego Biurrun
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
763 2effd274 Fabrice Bellard
                &len);
764 050056d0 Baptiste Coudurier
    if (fd < 0) {
765
        http_log("error during accept %s\n", strerror(errno));
766 2effd274 Fabrice Bellard
        return;
767 050056d0 Baptiste Coudurier
    }
768 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(fd, 1);
769 2effd274 Fabrice Bellard
770 0bdd8b85 Baptiste Coudurier
    if (nb_connections >= nb_max_connections) {
771
        http_send_too_busy_reply(fd);
772 2effd274 Fabrice Bellard
        goto fail;
773 0bdd8b85 Baptiste Coudurier
    }
774 115329f1 Diego Biurrun
775 2effd274 Fabrice Bellard
    /* add a new connection */
776
    c = av_mallocz(sizeof(HTTPContext));
777
    if (!c)
778
        goto fail;
779 115329f1 Diego Biurrun
780 2effd274 Fabrice Bellard
    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 8bc80f8b Philip Gladstone
788
    c->next = first_http_ctx;
789
    first_http_ctx = c;
790 2effd274 Fabrice Bellard
    nb_connections++;
791 115329f1 Diego Biurrun
792 2effd274 Fabrice Bellard
    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
    }
801 d96633bb Alex Beregszaszi
    closesocket(fd);
802 2effd274 Fabrice Bellard
}
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;
816 611c5741 Alex Beregszaszi
        if (c1 == c)
817 2effd274 Fabrice Bellard
            *cp = c->next;
818 611c5741 Alex Beregszaszi
        else
819 2effd274 Fabrice Bellard
            cp = &c1->next;
820
    }
821
822 bc351386 Fabrice Bellard
    /* 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 2effd274 Fabrice Bellard
    /* remove connection associated resources */
829
    if (c->fd >= 0)
830 d96633bb Alex Beregszaszi
        closesocket(c->fd);
831 2effd274 Fabrice Bellard
    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];
835 611c5741 Alex Beregszaszi
            if (st->codec->codec)
836 01f4895c Michael Niedermayer
                avcodec_close(st->codec);
837 2effd274 Fabrice Bellard
        }
838
        av_close_input_file(c->fmt_in);
839
    }
840
841
    /* free RTP output streams if any */
842
    nb_streams = 0;
843 115329f1 Diego Biurrun
    if (c->stream)
844 2effd274 Fabrice Bellard
        nb_streams = c->stream->nb_streams;
845 115329f1 Diego Biurrun
846 2effd274 Fabrice Bellard
    for(i=0;i<nb_streams;i++) {
847
        ctx = c->rtp_ctx[i];
848
        if (ctx) {
849
            av_write_trailer(ctx);
850 ea4f8aab Howard Chu
            av_metadata_free(&ctx->metadata);
851
            av_free(ctx->streams[0]);
852 2effd274 Fabrice Bellard
            av_free(ctx);
853
        }
854
        h = c->rtp_handles[i];
855 611c5741 Alex Beregszaszi
        if (h)
856 2effd274 Fabrice Bellard
            url_close(h);
857
    }
858 115329f1 Diego Biurrun
859 b88ba823 Mark Hills
    ctx = &c->fmt_ctx;
860
861 637b638e Baptiste Coudurier
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
862 87638494 Philip Gladstone
        if (ctx->oformat) {
863
            /* prepare header */
864
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
865
                av_write_trailer(ctx);
866 f8b06be9 Baptiste Coudurier
                av_freep(&c->pb_buffer);
867 899681cd Björn Axelsson
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
868 87638494 Philip Gladstone
            }
869
        }
870
    }
871
872 115329f1 Diego Biurrun
    for(i=0; i<ctx->nb_streams; i++)
873 0bd53967 Alex Beregszaszi
        av_free(ctx->streams[i]);
874 f0ef6240 Philip Gladstone
875 edfdd798 Alex Beregszaszi
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
876 6edd6884 Fabrice Bellard
        current_bandwidth -= c->stream->bandwidth;
877 5400e092 Alex Beregszaszi
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
884 2effd274 Fabrice Bellard
    av_freep(&c->pb_buffer);
885 bc351386 Fabrice Bellard
    av_freep(&c->packet_buffer);
886 2effd274 Fabrice Bellard
    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;
894 115329f1 Diego Biurrun
895 85f07f22 Fabrice Bellard
    switch(c->state) {
896
    case HTTPSTATE_WAIT_REQUEST:
897 2effd274 Fabrice Bellard
    case RTSPSTATE_WAIT_REQUEST:
898 85f07f22 Fabrice Bellard
        /* 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 1bc1cfdd Giancarlo Formicuccia
    read_loop:
909 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, 1, 0);
910 85f07f22 Fabrice Bellard
        if (len < 0) {
911 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
912
                ff_neterrno() != FF_NETERROR(EINTR))
913 85f07f22 Fabrice Bellard
                return -1;
914
        } else if (len == 0) {
915
            return -1;
916
        } else {
917 94d9ad5f Giancarlo Formicuccia
            /* search for end of request. */
918 0c1a9eda Zdenek Kabelac
            uint8_t *ptr;
919 85f07f22 Fabrice Bellard
            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 2effd274 Fabrice Bellard
                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 85f07f22 Fabrice Bellard
                    return -1;
931
            } else if (ptr >= c->buffer_end) {
932
                /* request too long: cannot do anything */
933
                return -1;
934 1bc1cfdd Giancarlo Formicuccia
            } else goto read_loop;
935 85f07f22 Fabrice Bellard
        }
936
        break;
937
938
    case HTTPSTATE_SEND_HEADER:
939
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
940
            return -1;
941
942 2effd274 Fabrice Bellard
        /* no need to write if no events */
943 85f07f22 Fabrice Bellard
        if (!(c->poll_entry->revents & POLLOUT))
944
            return 0;
945 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
946 85f07f22 Fabrice Bellard
        if (len < 0) {
947 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
948
                ff_neterrno() != FF_NETERROR(EINTR)) {
949 85f07f22 Fabrice Bellard
                /* error : close connection */
950 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
951 85f07f22 Fabrice Bellard
                return -1;
952
            }
953
        } else {
954
            c->buffer_ptr += len;
955 2e04edb3 Philip Gladstone
            if (c->stream)
956
                c->stream->bytes_served += len;
957 a6e14edd Philip Gladstone
            c->data_count += len;
958 85f07f22 Fabrice Bellard
            if (c->buffer_ptr >= c->buffer_end) {
959 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
960 85f07f22 Fabrice Bellard
                /* if error, exit */
961 611c5741 Alex Beregszaszi
                if (c->http_error)
962 85f07f22 Fabrice Bellard
                    return -1;
963 2effd274 Fabrice Bellard
                /* all the buffer was sent : synchronize to the incoming stream */
964 85f07f22 Fabrice Bellard
                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 2effd274 Fabrice Bellard
        /* 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;
979 115329f1 Diego Biurrun
980 2effd274 Fabrice Bellard
            /* no need to read if no events */
981
            if (!(c->poll_entry->revents & POLLOUT))
982
                return 0;
983
        }
984 5eb765ef Philip Gladstone
        if (http_send_data(c) < 0)
985 85f07f22 Fabrice Bellard
            return -1;
986 638831aa Alex Beregszaszi
        /* close connection if trailer sent */
987
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
988
            return -1;
989 85f07f22 Fabrice Bellard
        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 a6e14edd Philip Gladstone
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1002 85f07f22 Fabrice Bellard
            return -1;
1003
1004
        /* nothing to do, we'll be waken up by incoming feed packets */
1005
        break;
1006 2effd274 Fabrice Bellard
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;
1015 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1016 2effd274 Fabrice Bellard
        if (len < 0) {
1017 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1018
                ff_neterrno() != FF_NETERROR(EINTR)) {
1019 2effd274 Fabrice Bellard
                /* 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 bc351386 Fabrice Bellard
    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;
1041 c60202df Alex Beregszaszi
        len = send(c->fd, c->packet_buffer_ptr,
1042
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1043 bc351386 Fabrice Bellard
        if (len < 0) {
1044 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1045
                ff_neterrno() != FF_NETERROR(EINTR)) {
1046 bc351386 Fabrice Bellard
                /* 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 2effd274 Fabrice Bellard
    case HTTPSTATE_READY:
1060
        /* nothing to do */
1061
        break;
1062 85f07f22 Fabrice Bellard
    default:
1063
        return -1;
1064
    }
1065
    return 0;
1066
}
1067
1068 3120d2a2 Philip Gladstone
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 cde25790 Philip Gladstone
                memset(rates, 0xff, ratelen);
1086 3120d2a2 Philip Gladstone
1087
                while (1) {
1088
                    while (*q && *q != '\n' && *q != ':')
1089
                        q++;
1090
1091 611c5741 Alex Beregszaszi
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1092 3120d2a2 Philip Gladstone
                        break;
1093 611c5741 Alex Beregszaszi
1094 3120d2a2 Philip Gladstone
                    stream_no--;
1095 611c5741 Alex Beregszaszi
                    if (stream_no < ratelen && stream_no >= 0)
1096 3120d2a2 Philip Gladstone
                        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 cde25790 Philip Gladstone
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1116 3120d2a2 Philip Gladstone
{
1117
    int i;
1118 cde25790 Philip Gladstone
    int best_bitrate = 100000000;
1119
    int best = -1;
1120
1121
    for (i = 0; i < feed->nb_streams; i++) {
1122 01f4895c Michael Niedermayer
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1123 cde25790 Philip Gladstone
1124
        if (feed_codec->codec_id != codec->codec_id ||
1125
            feed_codec->sample_rate != codec->sample_rate ||
1126
            feed_codec->width != codec->width ||
1127 611c5741 Alex Beregszaszi
            feed_codec->height != codec->height)
1128 cde25790 Philip Gladstone
            continue;
1129
1130
        /* Potential stream */
1131
1132 115329f1 Diego Biurrun
        /* We want the fastest stream less than bit_rate, or the slowest
1133 cde25790 Philip Gladstone
         * 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 3120d2a2 Philip Gladstone
1158 001bcd29 Philip Gladstone
    /* Not much we can do for a feed */
1159
    if (!req->feed)
1160
        return 0;
1161
1162 3120d2a2 Philip Gladstone
    for (i = 0; i < req->nb_streams; i++) {
1163 01f4895c Michael Niedermayer
        AVCodecContext *codec = req->streams[i]->codec;
1164 3120d2a2 Philip Gladstone
1165
        switch(rates[i]) {
1166
            case 0:
1167 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = req->feed_streams[i];
1168 3120d2a2 Philip Gladstone
                break;
1169
            case 1:
1170 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1171 3120d2a2 Philip Gladstone
                break;
1172
            case 2:
1173 cde25790 Philip Gladstone
                /* 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 3120d2a2 Philip Gladstone
                break;
1181
        }
1182
1183 cde25790 Philip Gladstone
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1184
            action_required = 1;
1185
    }
1186 3120d2a2 Philip Gladstone
1187 cde25790 Philip Gladstone
    return action_required;
1188
}
1189 3120d2a2 Philip Gladstone
1190
1191 cde25790 Philip Gladstone
static void do_switch_stream(HTTPContext *c, int i)
1192
{
1193
    if (c->switch_feed_streams[i] >= 0) {
1194 115329f1 Diego Biurrun
#ifdef PHILIP
1195 cde25790 Philip Gladstone
        c->feed_streams[i] = c->switch_feed_streams[i];
1196
#endif
1197 3120d2a2 Philip Gladstone
1198 cde25790 Philip Gladstone
        /* Now update the stream */
1199 3120d2a2 Philip Gladstone
    }
1200 cde25790 Philip Gladstone
    c->switch_feed_streams[i] = -1;
1201 3120d2a2 Philip Gladstone
}
1202 7434ba6d Philip Gladstone
1203 2effd274 Fabrice Bellard
/* 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
1232 c64c0a9b Benjamin Larsson
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 58f48adb Benjamin Larsson
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)
1380 8256c0a3 Philip Gladstone
{
1381
    enum IPAddressAction last_action = IP_DENY;
1382
    IPAddressACL *acl;
1383
    struct in_addr *src = &c->from_addr.sin_addr;
1384 2bd8416e Alex Beregszaszi
    unsigned long src_addr = src->s_addr;
1385 8256c0a3 Philip Gladstone
1386 58f48adb Benjamin Larsson
    for (acl = in_acl; acl; acl = acl->next) {
1387 611c5741 Alex Beregszaszi
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1388 8256c0a3 Philip Gladstone
            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
1396 58f48adb Benjamin Larsson
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
1416 829ac53d Fabrice Bellard
/* 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 */
1426 f7d78f36 Måns Rullgård
    av_strlcpy(file1, filename, sizeof(file1));
1427 829ac53d Fabrice Bellard
    p = strrchr(file1, '.');
1428
    if (p)
1429
        *p = '\0';
1430
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1431 f7d78f36 Måns Rullgård
        av_strlcpy(file2, stream->filename, sizeof(file2));
1432 829ac53d Fabrice Bellard
        p = strrchr(file2, '.');
1433
        if (p)
1434
            *p = '\0';
1435
        if (!strcmp(file1, file2)) {
1436 f7d78f36 Måns Rullgård
            av_strlcpy(filename, stream->filename, max_size);
1437 829ac53d Fabrice Bellard
            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 85f07f22 Fabrice Bellard
/* parse http request and prepare header */
1452
static int http_parse_request(HTTPContext *c)
1453
{
1454
    char *p;
1455 829ac53d Fabrice Bellard
    enum RedirType redir_type;
1456 85f07f22 Fabrice Bellard
    char cmd[32];
1457 bae79c04 Alex Beregszaszi
    char info[1024], filename[1024];
1458 85f07f22 Fabrice Bellard
    char url[1024], *q;
1459
    char protocol[32];
1460
    char msg[1024];
1461
    const char *mime_type;
1462
    FFStream *stream;
1463 42a63c6a Philip Gladstone
    int i;
1464 3120d2a2 Philip Gladstone
    char ratebuf[32];
1465 cde25790 Philip Gladstone
    char *useragent = 0;
1466 85f07f22 Fabrice Bellard
1467
    p = c->buffer;
1468 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), (const char **)&p);
1469 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
1470 7434ba6d Philip Gladstone
1471 85f07f22 Fabrice Bellard
    if (!strcmp(cmd, "GET"))
1472 edfdd798 Alex Beregszaszi
        c->post = 0;
1473 85f07f22 Fabrice Bellard
    else if (!strcmp(cmd, "POST"))
1474 edfdd798 Alex Beregszaszi
        c->post = 1;
1475 85f07f22 Fabrice Bellard
    else
1476
        return -1;
1477
1478 2effd274 Fabrice Bellard
    get_word(url, sizeof(url), (const char **)&p);
1479 f7d78f36 Måns Rullgård
    av_strlcpy(c->url, url, sizeof(c->url));
1480 7434ba6d Philip Gladstone
1481 2effd274 Fabrice Bellard
    get_word(protocol, sizeof(protocol), (const char **)&p);
1482 85f07f22 Fabrice Bellard
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1483
        return -1;
1484 7434ba6d Philip Gladstone
1485 f7d78f36 Måns Rullgård
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1486 90f9c440 Alex Beregszaszi
1487
    if (ffserver_debug)
1488 77553ae3 Baptiste Coudurier
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1489 115329f1 Diego Biurrun
1490 85f07f22 Fabrice Bellard
    /* find the filename and the optional info string in the request */
1491 bae79c04 Alex Beregszaszi
    p = strchr(url, '?');
1492 85f07f22 Fabrice Bellard
    if (p) {
1493 f7d78f36 Måns Rullgård
        av_strlcpy(info, p, sizeof(info));
1494 85f07f22 Fabrice Bellard
        *p = '\0';
1495 611c5741 Alex Beregszaszi
    } else
1496 85f07f22 Fabrice Bellard
        info[0] = '\0';
1497
1498 f7d78f36 Måns Rullgård
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1499 bae79c04 Alex Beregszaszi
1500 cde25790 Philip Gladstone
    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 829ac53d Fabrice Bellard
    redir_type = REDIR_NONE;
1515 aa13b573 Stefano Sabatini
    if (av_match_ext(filename, "asx")) {
1516 829ac53d Fabrice Bellard
        redir_type = REDIR_ASX;
1517 7434ba6d Philip Gladstone
        filename[strlen(filename)-1] = 'f';
1518 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "asf") &&
1519 cde25790 Philip Gladstone
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1520
        /* if this isn't WMP or lookalike, return the redirector file */
1521 829ac53d Fabrice Bellard
        redir_type = REDIR_ASF;
1522 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "rpm,ram")) {
1523 829ac53d Fabrice Bellard
        redir_type = REDIR_RAM;
1524 42a63c6a Philip Gladstone
        strcpy(filename + strlen(filename)-2, "m");
1525 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "rtsp")) {
1526 829ac53d Fabrice Bellard
        redir_type = REDIR_RTSP;
1527 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1528 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "sdp")) {
1529 829ac53d Fabrice Bellard
        redir_type = REDIR_SDP;
1530 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1531 42a63c6a Philip Gladstone
    }
1532 115329f1 Diego Biurrun
1533 bae79c04 Alex Beregszaszi
    // "redirect" / request to index.html
1534
    if (!strlen(filename))
1535 f7d78f36 Måns Rullgård
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1536 bae79c04 Alex Beregszaszi
1537 85f07f22 Fabrice Bellard
    stream = first_stream;
1538
    while (stream != NULL) {
1539 8256c0a3 Philip Gladstone
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1540 85f07f22 Fabrice Bellard
            break;
1541
        stream = stream->next;
1542
    }
1543
    if (stream == NULL) {
1544 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1545 77553ae3 Baptiste Coudurier
        http_log("File '%s' not found\n", url);
1546 85f07f22 Fabrice Bellard
        goto send_error;
1547
    }
1548 42a63c6a Philip Gladstone
1549 cde25790 Philip Gladstone
    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;
1556 a3aa4fed Baptiste Coudurier
        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);
1564 cde25790 Philip Gladstone
        /* 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 3120d2a2 Philip Gladstone
    /* If this is WMP, get the rate information */
1572
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1573 cde25790 Philip Gladstone
        if (modify_current_stream(c, ratebuf)) {
1574 37d3e066 Aurelien Jacobs
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1575 cde25790 Philip Gladstone
                if (c->switch_feed_streams[i] >= 0)
1576
                    do_switch_stream(c, i);
1577
            }
1578
        }
1579 3120d2a2 Philip Gladstone
    }
1580
1581 d8f28a77 Baptiste Coudurier
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1582
        current_bandwidth += stream->bandwidth;
1583
1584 755bfeab Diego Biurrun
    /* If already streaming this feed, do not let start another feeder. */
1585 d0a5513b Alex Beregszaszi
    if (stream->feed_opened) {
1586
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1587 77553ae3 Baptiste Coudurier
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1588 d0a5513b Alex Beregszaszi
        goto send_error;
1589
    }
1590
1591 edfdd798 Alex Beregszaszi
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1592 42a63c6a Philip Gladstone
        c->http_error = 200;
1593
        q = c->buffer;
1594 a3aa4fed Baptiste Coudurier
        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 0be4b8d9 Baptiste Coudurier
                      "<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 a3aa4fed Baptiste Coudurier
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1603 42a63c6a Philip Gladstone
        /* prepare output buffer */
1604
        c->buffer_ptr = c->buffer;
1605
        c->buffer_end = q;
1606
        c->state = HTTPSTATE_SEND_HEADER;
1607
        return 0;
1608
    }
1609 115329f1 Diego Biurrun
1610 829ac53d Fabrice Bellard
    if (redir_type != REDIR_NONE) {
1611 7434ba6d Philip Gladstone
        char *hostinfo = 0;
1612 115329f1 Diego Biurrun
1613 7434ba6d Philip Gladstone
        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 829ac53d Fabrice Bellard
                    switch(redir_type) {
1644
                    case REDIR_ASX:
1645 a3aa4fed Baptiste Coudurier
                        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);
1653 829ac53d Fabrice Bellard
                        break;
1654
                    case REDIR_RAM:
1655 a3aa4fed Baptiste Coudurier
                        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);
1661 829ac53d Fabrice Bellard
                        break;
1662
                    case REDIR_ASF:
1663 a3aa4fed Baptiste Coudurier
                        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);
1669 829ac53d Fabrice Bellard
                        break;
1670
                    case REDIR_RTSP:
1671
                        {
1672
                            char hostname[256], *p;
1673
                            /* extract only hostname */
1674 f7d78f36 Måns Rullgård
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1675 829ac53d Fabrice Bellard
                            p = strrchr(hostname, ':');
1676
                            if (p)
1677
                                *p = '\0';
1678 a3aa4fed Baptiste Coudurier
                            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);
1684 829ac53d Fabrice Bellard
                        }
1685
                        break;
1686
                    case REDIR_SDP:
1687
                        {
1688 0c1a9eda Zdenek Kabelac
                            uint8_t *sdp_data;
1689 829ac53d Fabrice Bellard
                            int sdp_data_size, len;
1690
                            struct sockaddr_in my_addr;
1691
1692 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1693
                                          "HTTP/1.0 200 OK\r\n"
1694
                                          "Content-type: application/sdp\r\n"
1695
                                          "\r\n");
1696 829ac53d Fabrice Bellard
1697
                            len = sizeof(my_addr);
1698
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1699 115329f1 Diego Biurrun
1700 829ac53d Fabrice Bellard
                            /* XXX: should use a dynamic buffer */
1701 115329f1 Diego Biurrun
                            sdp_data_size = prepare_sdp_description(stream,
1702
                                                                    &sdp_data,
1703 829ac53d Fabrice Bellard
                                                                    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:
1713 0f4e8165 Ronald S. Bultje
                        abort();
1714 829ac53d Fabrice Bellard
                        break;
1715 2effd274 Fabrice Bellard
                    }
1716 7434ba6d Philip Gladstone
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 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1727 7434ba6d Philip Gladstone
        goto send_error;
1728 85f07f22 Fabrice Bellard
    }
1729
1730 a6e14edd Philip Gladstone
    stream->conns_served++;
1731 7434ba6d Philip Gladstone
1732 85f07f22 Fabrice Bellard
    /* XXX: add there authenticate and IP match */
1733
1734 edfdd798 Alex Beregszaszi
    if (c->post) {
1735 85f07f22 Fabrice Bellard
        /* if post, it means a feed is being sent */
1736
        if (!stream->is_feed) {
1737 e16190fa Diego Biurrun
            /* However it might be a status report from WMP! Let us log the
1738
             * data as it might come in handy one day. */
1739 7434ba6d Philip Gladstone
            char *logline = 0;
1740 3120d2a2 Philip Gladstone
            int client_id = 0;
1741 115329f1 Diego Biurrun
1742 7434ba6d Philip Gladstone
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1743
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1744
                    logline = p;
1745
                    break;
1746
                }
1747 611c5741 Alex Beregszaszi
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1748 3120d2a2 Philip Gladstone
                    client_id = strtol(p + 18, 0, 10);
1749 7434ba6d Philip Gladstone
                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 7906085f Falk Hüffner
                    http_log("%.*s\n", (int) (eol - logline), logline);
1765 7434ba6d Philip Gladstone
                    c->suppress_log = 1;
1766
                }
1767
            }
1768 3120d2a2 Philip Gladstone
1769 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1770
            http_log("\nGot request:\n%s\n", c->buffer);
1771 3120d2a2 Philip Gladstone
#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
1782 2d563d2f Alex Beregszaszi
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1783
                    wmpc->switch_pending = 1;
1784 3120d2a2 Philip Gladstone
            }
1785 115329f1 Diego Biurrun
1786 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "POST command not handled");
1787 cb275dd9 Philip Gladstone
            c->stream = 0;
1788 85f07f22 Fabrice Bellard
            goto send_error;
1789
        }
1790
        if (http_start_receive_data(c) < 0) {
1791 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "could not open feed");
1792 85f07f22 Fabrice Bellard
            goto send_error;
1793
        }
1794
        c->http_error = 0;
1795
        c->state = HTTPSTATE_RECEIVE_DATA;
1796
        return 0;
1797
    }
1798
1799 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1800 611c5741 Alex Beregszaszi
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1801 cde25790 Philip Gladstone
        http_log("\nGot request:\n%s\n", c->buffer);
1802 3120d2a2 Philip Gladstone
#endif
1803
1804 85f07f22 Fabrice Bellard
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1805 dca21085 Stefano Sabatini
        goto send_status;
1806 85f07f22 Fabrice Bellard
1807
    /* open input stream */
1808
    if (open_input_stream(c, info) < 0) {
1809 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1810 85f07f22 Fabrice Bellard
        goto send_error;
1811
    }
1812
1813
    /* prepare http header */
1814
    q = c->buffer;
1815 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1816 85f07f22 Fabrice Bellard
    mime_type = c->stream->fmt->mime_type;
1817
    if (!mime_type)
1818 087fa475 Alex Beregszaszi
        mime_type = "application/x-octet-stream";
1819 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1820 85f07f22 Fabrice Bellard
1821
    /* for asf, we need extra headers */
1822 8256c0a3 Philip Gladstone
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1823 3120d2a2 Philip Gladstone
        /* Need to allocate a client id */
1824
1825 042819c5 Baptiste Coudurier
        c->wmp_client_id = av_lfg_get(&random_state);
1826 3120d2a2 Philip Gladstone
1827 d445a7e9 Philip Gladstone
        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 85f07f22 Fabrice Bellard
    }
1829 d445a7e9 Philip Gladstone
    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");
1831 115329f1 Diego Biurrun
1832 85f07f22 Fabrice Bellard
    /* 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;
1841 a3aa4fed Baptiste Coudurier
    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"
1845 5e567aae Diego Biurrun
                  "<html>\n"
1846
                  "<head><title>404 Not Found</title></head>\n"
1847
                  "<body>%s</body>\n"
1848
                  "</html>\n", msg);
1849 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1850
    c->buffer_ptr = c->buffer;
1851
    c->buffer_end = q;
1852
    c->state = HTTPSTATE_SEND_HEADER;
1853
    return 0;
1854 dca21085 Stefano Sabatini
 send_status:
1855
    compute_status(c);
1856 85f07f22 Fabrice Bellard
    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 0c1a9eda Zdenek Kabelac
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1863 2ac887ba Philip Gladstone
{
1864
    static const char *suffix = " kMGTP";
1865
    const char *s;
1866
1867 611c5741 Alex Beregszaszi
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1868 2ac887ba Philip Gladstone
1869 4733abcb Måns Rullgård
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1870 2ac887ba Philip Gladstone
}
1871
1872 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c)
1873 85f07f22 Fabrice Bellard
{
1874
    HTTPContext *c1;
1875
    FFStream *stream;
1876 2effd274 Fabrice Bellard
    char *p;
1877 85f07f22 Fabrice Bellard
    time_t ti;
1878 2effd274 Fabrice Bellard
    int i, len;
1879 899681cd Björn Axelsson
    ByteIOContext *pb;
1880 cde25790 Philip Gladstone
1881 899681cd Björn Axelsson
    if (url_open_dyn_buf(&pb) < 0) {
1882 2effd274 Fabrice Bellard
        /* XXX: return an error ? */
1883 cde25790 Philip Gladstone
        c->buffer_ptr = c->buffer;
1884 2effd274 Fabrice Bellard
        c->buffer_end = c->buffer;
1885
        return;
1886 cde25790 Philip Gladstone
    }
1887 85f07f22 Fabrice Bellard
1888 2effd274 Fabrice Bellard
    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");
1892 115329f1 Diego Biurrun
1893 5e567aae Diego Biurrun
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1894 0679719d Erik Hovland
    if (c->stream->feed_filename[0])
1895 2effd274 Fabrice Bellard
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1896 5e567aae Diego Biurrun
    url_fprintf(pb, "</head>\n<body>");
1897
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1898 85f07f22 Fabrice Bellard
    /* format status */
1899 5e567aae Diego Biurrun
    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");
1902 85f07f22 Fabrice Bellard
    stream = first_stream;
1903
    while (stream != NULL) {
1904 42a63c6a Philip Gladstone
        char sfilename[1024];
1905
        char *eosf;
1906
1907 a6e14edd Philip Gladstone
        if (stream->feed != stream) {
1908 f7d78f36 Måns Rullgård
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1909 a6e14edd Philip Gladstone
            eosf = sfilename + strlen(sfilename);
1910
            if (eosf - sfilename >= 4) {
1911 611c5741 Alex Beregszaszi
                if (strcmp(eosf - 4, ".asf") == 0)
1912 a6e14edd Philip Gladstone
                    strcpy(eosf - 4, ".asx");
1913 611c5741 Alex Beregszaszi
                else if (strcmp(eosf - 3, ".rm") == 0)
1914 a6e14edd Philip Gladstone
                    strcpy(eosf - 3, ".ram");
1915 25e3e53d Luca Abeni
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1916 829ac53d Fabrice Bellard
                    /* generate a sample RTSP director if
1917
                       unicast. Generate an SDP redirector if
1918
                       multicast */
1919 2effd274 Fabrice Bellard
                    eosf = strrchr(sfilename, '.');
1920
                    if (!eosf)
1921
                        eosf = sfilename + strlen(sfilename);
1922 829ac53d Fabrice Bellard
                    if (stream->is_multicast)
1923
                        strcpy(eosf, ".sdp");
1924
                    else
1925
                        strcpy(eosf, ".rtsp");
1926 a6e14edd Philip Gladstone
                }
1927 42a63c6a Philip Gladstone
            }
1928 115329f1 Diego Biurrun
1929 5e567aae Diego Biurrun
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1930 a6e14edd Philip Gladstone
                         sfilename, stream->filename);
1931 2effd274 Fabrice Bellard
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1932 2ac887ba Philip Gladstone
                        stream->conns_served);
1933 2effd274 Fabrice Bellard
            fmt_bytecount(pb, stream->bytes_served);
1934 a6e14edd Philip Gladstone
            switch(stream->stream_type) {
1935 ace21da3 Baptiste Coudurier
            case STREAM_TYPE_LIVE: {
1936 a6e14edd Philip Gladstone
                    int audio_bit_rate = 0;
1937
                    int video_bit_rate = 0;
1938 58445440 Zdenek Kabelac
                    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 a6e14edd Philip Gladstone
1943
                    for(i=0;i<stream->nb_streams;i++) {
1944
                        AVStream *st = stream->streams[i];
1945 01f4895c Michael Niedermayer
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1946
                        switch(st->codec->codec_type) {
1947 72415b2a Stefano Sabatini
                        case AVMEDIA_TYPE_AUDIO:
1948 01f4895c Michael Niedermayer
                            audio_bit_rate += st->codec->bit_rate;
1949 a6e14edd Philip Gladstone
                            if (codec) {
1950
                                if (*audio_codec_name)
1951
                                    audio_codec_name_extra = "...";
1952
                                audio_codec_name = codec->name;
1953
                            }
1954
                            break;
1955 72415b2a Stefano Sabatini
                        case AVMEDIA_TYPE_VIDEO:
1956 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1957 a6e14edd Philip Gladstone
                            if (codec) {
1958
                                if (*video_codec_name)
1959
                                    video_codec_name_extra = "...";
1960
                                video_codec_name = codec->name;
1961
                            }
1962
                            break;
1963 72415b2a Stefano Sabatini
                        case AVMEDIA_TYPE_DATA:
1964 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1965 e240a0bb Fabrice Bellard
                            break;
1966 a6e14edd Philip Gladstone
                        default:
1967 0f4e8165 Ronald S. Bultje
                            abort();
1968 79c4ea3c Philip Gladstone
                        }
1969 85f07f22 Fabrice Bellard
                    }
1970 5e567aae Diego Biurrun
                    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",
1971 a6e14edd Philip Gladstone
                                 stream->fmt->name,
1972 6edd6884 Fabrice Bellard
                                 stream->bandwidth,
1973 a6e14edd Philip Gladstone
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1974
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1975 611c5741 Alex Beregszaszi
                    if (stream->feed)
1976 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1977 611c5741 Alex Beregszaszi
                    else
1978 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1979 2effd274 Fabrice Bellard
                    url_fprintf(pb, "\n");
1980 85f07f22 Fabrice Bellard
                }
1981 a6e14edd Philip Gladstone
                break;
1982
            default:
1983 5e567aae Diego Biurrun
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1984 a6e14edd Philip Gladstone
                break;
1985 85f07f22 Fabrice Bellard
            }
1986
        }
1987
        stream = stream->next;
1988
    }
1989 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
1990 a6e14edd Philip Gladstone
1991
    stream = first_stream;
1992
    while (stream != NULL) {
1993
        if (stream->feed == stream) {
1994 2effd274 Fabrice Bellard
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1995 cde25790 Philip Gladstone
            if (stream->pid) {
1996 2effd274 Fabrice Bellard
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1997 cde25790 Philip Gladstone
1998 2effd274 Fabrice Bellard
#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 */
2004 115329f1 Diego Biurrun
                    snprintf(ps_cmd, sizeof(ps_cmd),
2005
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2006 2effd274 Fabrice Bellard
                             stream->pid);
2007 115329f1 Diego Biurrun
2008 2effd274 Fabrice Bellard
                    pid_stat = popen(ps_cmd, "r");
2009
                    if (pid_stat) {
2010
                        char cpuperc[10];
2011
                        char cpuused[64];
2012 115329f1 Diego Biurrun
2013
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2014 2effd274 Fabrice Bellard
                                   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 cde25790 Philip Gladstone
                    }
2020
                }
2021
#endif
2022
2023 2effd274 Fabrice Bellard
                url_fprintf(pb, "<p>");
2024 cde25790 Philip Gladstone
            }
2025 2effd274 Fabrice Bellard
            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 a6e14edd Philip Gladstone
2027
            for (i = 0; i < stream->nb_streams; i++) {
2028
                AVStream *st = stream->streams[i];
2029 01f4895c Michael Niedermayer
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2030 b29f97d1 Zdenek Kabelac
                const char *type = "unknown";
2031 b582f314 Philip Gladstone
                char parameters[64];
2032
2033
                parameters[0] = 0;
2034 a6e14edd Philip Gladstone
2035 01f4895c Michael Niedermayer
                switch(st->codec->codec_type) {
2036 72415b2a Stefano Sabatini
                case AVMEDIA_TYPE_AUDIO:
2037 a6e14edd Philip Gladstone
                    type = "audio";
2038 acdc8520 Alex Beregszaszi
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2039 a6e14edd Philip Gladstone
                    break;
2040 72415b2a Stefano Sabatini
                case AVMEDIA_TYPE_VIDEO:
2041 a6e14edd Philip Gladstone
                    type = "video";
2042 01f4895c Michael Niedermayer
                    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 a6e14edd Philip Gladstone
                    break;
2045
                default:
2046 0f4e8165 Ronald S. Bultje
                    abort();
2047 a6e14edd Philip Gladstone
                }
2048 2effd274 Fabrice Bellard
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2049 01f4895c Michael Niedermayer
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2050 a6e14edd Philip Gladstone
            }
2051 2effd274 Fabrice Bellard
            url_fprintf(pb, "</table>\n");
2052 a6e14edd Philip Gladstone
2053 115329f1 Diego Biurrun
        }
2054 a6e14edd Philip Gladstone
        stream = stream->next;
2055
    }
2056 115329f1 Diego Biurrun
2057 85f07f22 Fabrice Bellard
    /* connection status */
2058 5e567aae Diego Biurrun
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
2059 85f07f22 Fabrice Bellard
2060 5e567aae Diego Biurrun
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
2061 85f07f22 Fabrice Bellard
                 nb_connections, nb_max_connections);
2062
2063 5e567aae Diego Biurrun
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2064 6edd6884 Fabrice Bellard
                 current_bandwidth, max_bandwidth);
2065 42a63c6a Philip Gladstone
2066 5e567aae Diego Biurrun
    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");
2068 85f07f22 Fabrice Bellard
    c1 = first_http_ctx;
2069
    i = 0;
2070 2effd274 Fabrice Bellard
    while (c1 != NULL) {
2071 cde25790 Philip Gladstone
        int bitrate;
2072
        int j;
2073
2074
        bitrate = 0;
2075 2effd274 Fabrice Bellard
        if (c1->stream) {
2076
            for (j = 0; j < c1->stream->nb_streams; j++) {
2077 2d563d2f Alex Beregszaszi
                if (!c1->stream->feed)
2078 01f4895c Michael Niedermayer
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2079 2d563d2f Alex Beregszaszi
                else if (c1->feed_streams[j] >= 0)
2080
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2081 cde25790 Philip Gladstone
            }
2082
        }
2083
2084 85f07f22 Fabrice Bellard
        i++;
2085
        p = inet_ntoa(c1->from_addr.sin_addr);
2086 5e567aae Diego Biurrun
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2087 115329f1 Diego Biurrun
                    i,
2088
                    c1->stream ? c1->stream->filename : "",
2089 2effd274 Fabrice Bellard
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2090 115329f1 Diego Biurrun
                    p,
2091 2effd274 Fabrice Bellard
                    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 85f07f22 Fabrice Bellard
        c1 = c1->next;
2100
    }
2101 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
2102 115329f1 Diego Biurrun
2103 85f07f22 Fabrice Bellard
    /* date */
2104
    ti = time(NULL);
2105
    p = ctime(&ti);
2106 5e567aae Diego Biurrun
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
2107
    url_fprintf(pb, "</body>\n</html>\n");
2108 85f07f22 Fabrice Bellard
2109 2effd274 Fabrice Bellard
    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 85f07f22 Fabrice Bellard
}
2113
2114 2effd274 Fabrice Bellard
/* check if the parser needs to be opened for stream i */
2115
static void open_parser(AVFormatContext *s, int i)
2116 85f07f22 Fabrice Bellard
{
2117 2effd274 Fabrice Bellard
    AVStream *st = s->streams[i];
2118
    AVCodec *codec;
2119 31def229 Philip Gladstone
2120 01f4895c Michael Niedermayer
    if (!st->codec->codec) {
2121
        codec = avcodec_find_decoder(st->codec->codec_id);
2122 2effd274 Fabrice Bellard
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2123 01f4895c Michael Niedermayer
            st->codec->parse_only = 1;
2124 611c5741 Alex Beregszaszi
            if (avcodec_open(st->codec, codec) < 0)
2125 01f4895c Michael Niedermayer
                st->codec->parse_only = 0;
2126 cde25790 Philip Gladstone
        }
2127
    }
2128 85f07f22 Fabrice Bellard
}
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;
2135 c351cc7f Baptiste Coudurier
    int buf_size, i, ret;
2136 0c1a9eda Zdenek Kabelac
    int64_t stream_pos;
2137 85f07f22 Fabrice Bellard
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) */
2143 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2144 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 0);
2145 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
2146
                return -1;
2147 ace21da3 Baptiste Coudurier
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
2148 f747e6d3 Philip Gladstone
            int prebuffer = strtol(buf, 0, 10);
2149 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2150 611c5741 Alex Beregszaszi
        } else
2151 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2152 85f07f22 Fabrice Bellard
    } else {
2153
        strcpy(input_filename, c->stream->feed_filename);
2154
        buf_size = 0;
2155
        /* compute position (relative time) */
2156 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2157 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 1);
2158 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
2159
                return -1;
2160 ace21da3 Baptiste Coudurier
        } else
2161 85f07f22 Fabrice Bellard
            stream_pos = 0;
2162
    }
2163
    if (input_filename[0] == '\0')
2164
        return -1;
2165
2166
    /* open stream */
2167 c351cc7f Baptiste Coudurier
    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);
2170 85f07f22 Fabrice Bellard
        return -1;
2171 2effd274 Fabrice Bellard
    }
2172 9dc0bc3d Luca Abeni
    s->flags |= AVFMT_FLAG_GENPTS;
2173 85f07f22 Fabrice Bellard
    c->fmt_in = s;
2174 85fe4ae0 Baptiste Coudurier
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2175 20f93c3c Baptiste Coudurier
        http_log("Could not find stream info '%s'\n", input_filename);
2176
        av_close_input_file(s);
2177
        return -1;
2178
    }
2179 115329f1 Diego Biurrun
2180 2effd274 Fabrice Bellard
    /* 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++) {
2188 115329f1 Diego Biurrun
        if (c->pts_stream_index == 0 &&
2189 72415b2a Stefano Sabatini
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2190 2effd274 Fabrice Bellard
            c->pts_stream_index = i;
2191
        }
2192
    }
2193 85f07f22 Fabrice Bellard
2194 e8d27bc3 Philip Gladstone
#if 1
2195 611c5741 Alex Beregszaszi
    if (c->fmt_in->iformat->read_seek)
2196 60a04f7f Baptiste Coudurier
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2197 e240a0bb Fabrice Bellard
#endif
2198 2effd274 Fabrice Bellard
    /* 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 85f07f22 Fabrice Bellard
    return 0;
2202
}
2203
2204 e240a0bb Fabrice Bellard
/* return the server clock (in us) */
2205
static int64_t get_server_clock(HTTPContext *c)
2206 2effd274 Fabrice Bellard
{
2207 e240a0bb Fabrice Bellard
    /* compute current pts value from system time */
2208 c3f58185 Alex Beregszaszi
    return (cur_time - c->start_time) * 1000;
2209 2effd274 Fabrice Bellard
}
2210
2211 e240a0bb Fabrice Bellard
/* 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 2effd274 Fabrice Bellard
{
2215 e240a0bb Fabrice Bellard
    int bytes_left, bytes_sent, frame_bytes;
2216 115329f1 Diego Biurrun
2217 e240a0bb Fabrice Bellard
    frame_bytes = c->cur_frame_bytes;
2218 611c5741 Alex Beregszaszi
    if (frame_bytes <= 0)
2219 e240a0bb Fabrice Bellard
        return c->cur_pts;
2220 611c5741 Alex Beregszaszi
    else {
2221 e240a0bb Fabrice Bellard
        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 2effd274 Fabrice Bellard
    }
2225
}
2226
2227
2228
static int http_prepare_data(HTTPContext *c)
2229
{
2230
    int i, len, ret;
2231
    AVFormatContext *ctx;
2232
2233 bc351386 Fabrice Bellard
    av_freep(&c->pb_buffer);
2234 2effd274 Fabrice Bellard
    switch(c->state) {
2235
    case HTTPSTATE_SEND_DATA_HEADER:
2236
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2237 2ef6c124 Stefano Sabatini
        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);
2241 2effd274 Fabrice Bellard
2242 3d9cc27d Baptiste Coudurier
        for(i=0;i<c->stream->nb_streams;i++) {
2243 2effd274 Fabrice Bellard
            AVStream *st;
2244 bb270c08 Diego Biurrun
            AVStream *src;
2245 2effd274 Fabrice Bellard
            st = av_mallocz(sizeof(AVStream));
2246
            c->fmt_ctx.streams[i] = st;
2247
            /* if file or feed, then just take streams from FFStream struct */
2248 115329f1 Diego Biurrun
            if (!c->stream->feed ||
2249 2effd274 Fabrice Bellard
                c->stream->feed == c->stream)
2250 7c054ea7 Philip Gladstone
                src = c->stream->streams[i];
2251 2effd274 Fabrice Bellard
            else
2252 7c054ea7 Philip Gladstone
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2253
2254 bb270c08 Diego Biurrun
            *st = *src;
2255
            st->priv_data = 0;
2256 01f4895c Michael Niedermayer
            st->codec->frame_number = 0; /* XXX: should be done in
2257 2effd274 Fabrice Bellard
                                           AVStream, not in codec */
2258
        }
2259 3d9cc27d Baptiste Coudurier
        /* set output format parameters */
2260
        c->fmt_ctx.oformat = c->stream->fmt;
2261
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2262
2263 2effd274 Fabrice Bellard
        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
        }
2270 899681cd Björn Axelsson
        c->fmt_ctx.pb->is_streamed = 1;
2271 2effd274 Fabrice Bellard
2272 8aae202e Baptiste Coudurier
        /*
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
2280 3c27199b Fabrice Bellard
        av_set_parameters(&c->fmt_ctx, NULL);
2281 929a9b75 Baptiste Coudurier
        if (av_write_header(&c->fmt_ctx) < 0) {
2282
            http_log("Error writing output header\n");
2283 f75cdda7 Alex Beregszaszi
            return -1;
2284 929a9b75 Baptiste Coudurier
        }
2285 ea4f8aab Howard Chu
        av_metadata_free(&c->fmt_ctx.metadata);
2286 2effd274 Fabrice Bellard
2287 899681cd Björn Axelsson
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2288 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2289
        c->buffer_end = c->pb_buffer + len;
2290
2291
        c->state = HTTPSTATE_SEND_DATA;
2292 85f07f22 Fabrice Bellard
        c->last_packet_sent = 0;
2293
        break;
2294
    case HTTPSTATE_SEND_DATA:
2295
        /* find a new packet */
2296 3b371676 Baptiste Coudurier
        /* 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 {
2307
            AVPacket pkt;
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 2effd274 Fabrice Bellard
                } else {
2316 3b371676 Baptiste Coudurier
                    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;
2322
                    } else {
2323
                    no_loop:
2324
                        /* must send trailer now because eof or error */
2325
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2326 1bc1cfdd Giancarlo Formicuccia
                    }
2327 3b371676 Baptiste Coudurier
                }
2328
            } else {
2329 084a8912 Baptiste Coudurier
                int source_index = pkt.stream_index;
2330 3b371676 Baptiste Coudurier
                /* 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;
2340 cde25790 Philip Gladstone
                        for(i=0;i<c->stream->nb_streams;i++) {
2341 3b371676 Baptiste Coudurier
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2342 cc947f04 Jean-Daniel Dupas
                                if (pkt.flags & AV_PKT_FLAG_KEY)
2343 3b371676 Baptiste Coudurier
                                    do_switch_stream(c, i);
2344
                            if (c->switch_feed_streams[i] >= 0)
2345
                                c->switch_pending = 1;
2346 cde25790 Philip Gladstone
                        }
2347 3b371676 Baptiste Coudurier
                    }
2348
                    for(i=0;i<c->stream->nb_streams;i++) {
2349 a5ba4ced Martin Storsjö
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2350 78728064 Baptiste Coudurier
                            AVStream *st = c->fmt_in->streams[source_index];
2351 3b371676 Baptiste Coudurier
                            pkt.stream_index = i;
2352 cc947f04 Jean-Daniel Dupas
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2353 72415b2a Stefano Sabatini
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2354 180b7026 Baptiste Coudurier
                                 c->stream->nb_streams == 1))
2355 0332f549 Baptiste Coudurier
                                c->got_key_frame = 1;
2356
                            if (!c->stream->send_on_key || c->got_key_frame)
2357 3b371676 Baptiste Coudurier
                                goto send_it;
2358
                        }
2359
                    }
2360
                } else {
2361
                    AVCodecContext *codec;
2362 dc3a6a36 Baptiste Coudurier
                    AVStream *ist, *ost;
2363
                send_it:
2364
                    ist = c->fmt_in->streams[source_index];
2365 3b371676 Baptiste Coudurier
                    /* 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 8f56ccca Baptiste Coudurier
                        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 3b371676 Baptiste Coudurier
                        /* find RTP context */
2375
                        c->packet_stream_index = pkt.stream_index;
2376
                        ctx = c->rtp_ctx[c->packet_stream_index];
2377
                        if(!ctx) {
2378 8a0b55ff Baptiste Coudurier
                            av_free_packet(&pkt);
2379 3b371676 Baptiste Coudurier
                            break;
2380 8a0b55ff Baptiste Coudurier
                        }
2381 3b371676 Baptiste Coudurier
                        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 3ab29d8e Baptiste Coudurier
                        codec = ctx->streams[pkt.stream_index]->codec;
2388 3b371676 Baptiste Coudurier
                    }
2389
2390
                    if (c->is_packetized) {
2391
                        int max_packet_size;
2392 90abbdba Ronald S. Bultje
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2393 3b371676 Baptiste Coudurier
                            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 3ab29d8e Baptiste Coudurier
                    ost = ctx->streams[pkt.stream_index];
2405
2406 b0675954 Baptiste Coudurier
                    ctx->pb->is_streamed = 1;
2407 3b371676 Baptiste Coudurier
                    if (pkt.dts != AV_NOPTS_VALUE)
2408 d80904cc Baptiste Coudurier
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2409 3b371676 Baptiste Coudurier
                    if (pkt.pts != AV_NOPTS_VALUE)
2410 d80904cc Baptiste Coudurier
                        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 3766ed72 Baptiste Coudurier
                    if (av_write_frame(ctx, &pkt) < 0) {
2413
                        http_log("Error writing frame to output\n");
2414 3b371676 Baptiste Coudurier
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2415 3766ed72 Baptiste Coudurier
                    }
2416 3b371676 Baptiste Coudurier
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 f747e6d3 Philip Gladstone
                    }
2427 85f07f22 Fabrice Bellard
                }
2428 3b371676 Baptiste Coudurier
                av_free_packet(&pkt);
2429 85f07f22 Fabrice Bellard
            }
2430 3b371676 Baptiste Coudurier
        }
2431 85f07f22 Fabrice Bellard
        break;
2432
    default:
2433
    case HTTPSTATE_SEND_DATA_TRAILER:
2434
        /* last packet test ? */
2435 2effd274 Fabrice Bellard
        if (c->last_packet_sent || c->is_packetized)
2436 85f07f22 Fabrice Bellard
            return -1;
2437 2effd274 Fabrice Bellard
        ctx = &c->fmt_ctx;
2438 85f07f22 Fabrice Bellard
        /* prepare header */
2439 2effd274 Fabrice Bellard
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2440
            /* XXX: potential leak */
2441
            return -1;
2442
        }
2443 58bd615f Baptiste Coudurier
        c->fmt_ctx.pb->is_streamed = 1;
2444 2effd274 Fabrice Bellard
        av_write_trailer(ctx);
2445 899681cd Björn Axelsson
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2446 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2447
        c->buffer_end = c->pb_buffer + len;
2448
2449 85f07f22 Fabrice Bellard
        c->last_packet_sent = 1;
2450
        break;
2451
    }
2452
    return 0;
2453
}
2454
2455
/* should convert the format at the same time */
2456 bc351386 Fabrice Bellard
/* send data starting at c->buffer_ptr to the output connection
2457
   (either UDP or TCP connection) */
2458 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c)
2459 85f07f22 Fabrice Bellard
{
2460 e240a0bb Fabrice Bellard
    int len, ret;
2461 85f07f22 Fabrice Bellard
2462 bc351386 Fabrice Bellard
    for(;;) {
2463
        if (c->buffer_ptr >= c->buffer_end) {
2464
            ret = http_prepare_data(c);
2465
            if (ret < 0)
2466
                return -1;
2467 611c5741 Alex Beregszaszi
            else if (ret != 0)
2468 bc351386 Fabrice Bellard
                /* state change requested */
2469
                break;
2470 2effd274 Fabrice Bellard
        } else {
2471 bc351386 Fabrice Bellard
            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 2effd274 Fabrice Bellard
                    return 0;
2479
                }
2480 bc351386 Fabrice Bellard
                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 e240a0bb Fabrice Bellard
                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
2496 90abbdba Ronald S. Bultje
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2497 bc351386 Fabrice Bellard
                    /* RTP packets are sent inside the RTSP TCP connection */
2498 899681cd Björn Axelsson
                    ByteIOContext *pb;
2499 bc351386 Fabrice Bellard
                    int interleaved_index, size;
2500
                    uint8_t header[4];
2501
                    HTTPContext *rtsp_c;
2502 115329f1 Diego Biurrun
2503 bc351386 Fabrice Bellard
                    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. */
2508 611c5741 Alex Beregszaszi
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2509 bc351386 Fabrice Bellard
                        break;
2510 899681cd Björn Axelsson
                    if (url_open_dyn_buf(&pb) < 0)
2511 bc351386 Fabrice Bellard
                        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 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2530 115329f1 Diego Biurrun
2531 e240a0bb Fabrice Bellard
                    /* send everything we can NOW */
2532 c60202df Alex Beregszaszi
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2534 611c5741 Alex Beregszaszi
                    if (len > 0)
2535 e240a0bb Fabrice Bellard
                        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;
2542 611c5741 Alex Beregszaszi
                    } else
2543 e240a0bb Fabrice Bellard
                        /* all data has been sent */
2544
                        av_freep(&c->packet_buffer);
2545
                } else {
2546
                    /* send RTP packet directly in UDP */
2547 bc351386 Fabrice Bellard
                    c->buffer_ptr += 4;
2548 115329f1 Diego Biurrun
                    url_write(c->rtp_handles[c->packet_stream_index],
2549 bc351386 Fabrice Bellard
                              c->buffer_ptr, len);
2550 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2551
                    /* here we continue as we can send several packets per 10 ms slot */
2552 bc351386 Fabrice Bellard
                }
2553
            } else {
2554
                /* TCP data output */
2555 c60202df Alex Beregszaszi
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2556 bc351386 Fabrice Bellard
                if (len < 0) {
2557 8da4034f Alex Beregszaszi
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2558 611c5741 Alex Beregszaszi
                        ff_neterrno() != FF_NETERROR(EINTR))
2559 bc351386 Fabrice Bellard
                        /* error : close connection */
2560
                        return -1;
2561 611c5741 Alex Beregszaszi
                    else
2562 bc351386 Fabrice Bellard
                        return 0;
2563 611c5741 Alex Beregszaszi
                } else
2564 bc351386 Fabrice Bellard
                    c->buffer_ptr += len;
2565 611c5741 Alex Beregszaszi
2566 e240a0bb Fabrice Bellard
                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 2effd274 Fabrice Bellard
            }
2572 85f07f22 Fabrice Bellard
        }
2573 bc351386 Fabrice Bellard
    } /* for(;;) */
2574 85f07f22 Fabrice Bellard
    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 e322ea48 Philip Gladstone
    /* Don't permit writing to this one */
2585
    if (c->stream->readonly)
2586
        return -1;
2587
2588 85f07f22 Fabrice Bellard
    /* open feed */
2589
    fd = open(c->stream->feed_filename, O_RDWR);
2590 929a9b75 Baptiste Coudurier
    if (fd < 0) {
2591
        http_log("Error opening feeder file: %s\n", strerror(errno));
2592 85f07f22 Fabrice Bellard
        return -1;
2593 929a9b75 Baptiste Coudurier
    }
2594 85f07f22 Fabrice Bellard
    c->feed_fd = fd;
2595 115329f1 Diego Biurrun
2596 861ec13a Baptiste Coudurier
    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 1f611549 Baptiste Coudurier
        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
        }
2606 861ec13a Baptiste Coudurier
    }
2607
2608 7e24aa0c Baptiste Coudurier
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2609 85f07f22 Fabrice Bellard
    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;
2616 fd7bec5e Måns Rullgård
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2617 85f07f22 Fabrice Bellard
    return 0;
2618
}
2619 115329f1 Diego Biurrun
2620 85f07f22 Fabrice Bellard
static int http_receive_data(HTTPContext *c)
2621
{
2622
    HTTPContext *c1;
2623 19c8c4ec Ronald S. Bultje
    int len, loop_run = 0;
2624 85f07f22 Fabrice Bellard
2625 19c8c4ec Ronald S. Bultje
    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 686d6f40 Howard Chu
            return 0;
2636 19c8c4ec Ronald S. Bultje
        } else if (len == 0) {
2637
            /* end of connection : close it */
2638
            goto fail;
2639
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2640
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2641
            c->chunk_size = strtol(c->buffer, 0, 16);
2642
            if (c->chunk_size == 0) // end of stream
2643
                goto fail;
2644
            c->buffer_ptr = c->buffer;
2645
            break;
2646
        } else if (++loop_run > 10) {
2647
            /* no chunk header, abort */
2648
            goto fail;
2649
        } else {
2650
            c->buffer_ptr++;
2651
        }
2652
    }
2653 a6e14edd Philip Gladstone
2654 19c8c4ec Ronald S. Bultje
    if (c->buffer_end > c->buffer_ptr) {
2655
        len = recv(c->fd, c->buffer_ptr,
2656
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2657 a6e14edd Philip Gladstone
        if (len < 0) {
2658 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2659 611c5741 Alex Beregszaszi
                ff_neterrno() != FF_NETERROR(EINTR))
2660 a6e14edd Philip Gladstone
                /* error : close connection */
2661
                goto fail;
2662 611c5741 Alex Beregszaszi
        } else if (len == 0)
2663 a6e14edd Philip Gladstone
            /* end of connection : close it */
2664
            goto fail;
2665 611c5741 Alex Beregszaszi
        else {
2666 19c8c4ec Ronald S. Bultje
            c->chunk_size -= len;
2667 a6e14edd Philip Gladstone
            c->buffer_ptr += len;
2668
            c->data_count += len;
2669 5eb765ef Philip Gladstone
            update_datarate(&c->datarate, c->data_count);
2670 a6e14edd Philip Gladstone
        }
2671
    }
2672
2673 d445a7e9 Philip Gladstone
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2674
        if (c->buffer[0] != 'f' ||
2675
            c->buffer[1] != 'm') {
2676
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2677
            goto fail;
2678
        }
2679
    }
2680
2681 85f07f22 Fabrice Bellard
    if (c->buffer_ptr >= c->buffer_end) {
2682 f747e6d3 Philip Gladstone
        FFStream *feed = c->stream;
2683 85f07f22 Fabrice Bellard
        /* a packet has been received : write it in the store, except
2684
           if header */