Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 6580d5e3

History | View | Annotate | Download (152 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 959da985 Stefano Sabatini
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32 245976da Diego Biurrun
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35 302879cb Luca Abeni
#include "libavformat/rtpdec.h"
36 245976da Diego Biurrun
#include "libavformat/rtsp.h"
37 959da985 Stefano Sabatini
#include "libavutil/avstring.h"
38 042819c5 Baptiste Coudurier
#include "libavutil/lfg.h"
39
#include "libavutil/random_seed.h"
40 7ab08864 Baptiste Coudurier
#include "libavcodec/opt.h"
41 85f07f22 Fabrice Bellard
#include <stdarg.h>
42
#include <unistd.h>
43
#include <fcntl.h>
44
#include <sys/ioctl.h>
45 b250f9c6 Aurelien Jacobs
#if HAVE_POLL_H
46 f8cda19e Luca Abeni
#include <poll.h>
47 b0c858d8 François Revol
#endif
48 85f07f22 Fabrice Bellard
#include <errno.h>
49
#include <sys/time.h>
50
#include <time.h>
51 5eb765ef Philip Gladstone
#include <sys/wait.h>
52 85f07f22 Fabrice Bellard
#include <signal.h>
53 b250f9c6 Aurelien Jacobs
#if HAVE_DLFCN_H
54 2effd274 Fabrice Bellard
#include <dlfcn.h>
55 6638d424 Philip Gladstone
#endif
56 2effd274 Fabrice Bellard
57 4ce5df08 Stefano Sabatini
#include "cmdutils.h"
58 85f07f22 Fabrice Bellard
59 64555bd9 Michael Niedermayer
const char program_name[] = "FFserver";
60 ea9c581f Stefano Sabatini
const int program_birth_year = 2000;
61 86074ed1 Stefano Sabatini
62 5a635bc7 Stefano Sabatini
static const OptionDef options[];
63
64 85f07f22 Fabrice Bellard
enum HTTPState {
65
    HTTPSTATE_WAIT_REQUEST,
66
    HTTPSTATE_SEND_HEADER,
67
    HTTPSTATE_SEND_DATA_HEADER,
68 2effd274 Fabrice Bellard
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
69 85f07f22 Fabrice Bellard
    HTTPSTATE_SEND_DATA_TRAILER,
70 115329f1 Diego Biurrun
    HTTPSTATE_RECEIVE_DATA,
71 2effd274 Fabrice Bellard
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
72
    HTTPSTATE_READY,
73
74
    RTSPSTATE_WAIT_REQUEST,
75
    RTSPSTATE_SEND_REPLY,
76 bc351386 Fabrice Bellard
    RTSPSTATE_SEND_PACKET,
77 85f07f22 Fabrice Bellard
};
78
79 9507a12e Baptiste Coudurier
static const char *http_state[] = {
80 2effd274 Fabrice Bellard
    "HTTP_WAIT_REQUEST",
81
    "HTTP_SEND_HEADER",
82
83 85f07f22 Fabrice Bellard
    "SEND_DATA_HEADER",
84
    "SEND_DATA",
85
    "SEND_DATA_TRAILER",
86
    "RECEIVE_DATA",
87
    "WAIT_FEED",
88 2effd274 Fabrice Bellard
    "READY",
89
90
    "RTSP_WAIT_REQUEST",
91
    "RTSP_SEND_REPLY",
92 bc351386 Fabrice Bellard
    "RTSP_SEND_PACKET",
93 85f07f22 Fabrice Bellard
};
94
95 cde25790 Philip Gladstone
#define IOBUFFER_INIT_SIZE 8192
96 85f07f22 Fabrice Bellard
97
/* timeouts are in ms */
98 2effd274 Fabrice Bellard
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
99
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
100
101 85f07f22 Fabrice Bellard
#define SYNC_TIMEOUT (10 * 1000)
102
103 b516ecdd Ronald S. Bultje
typedef struct RTSPActionServerSetup {
104
    uint32_t ipaddr;
105
    char transport_option[512];
106
} RTSPActionServerSetup;
107
108 5eb765ef Philip Gladstone
typedef struct {
109 0c1a9eda Zdenek Kabelac
    int64_t count1, count2;
110 c3f58185 Alex Beregszaszi
    int64_t time1, time2;
111 5eb765ef Philip Gladstone
} DataRateData;
112
113 85f07f22 Fabrice Bellard
/* context associated with one connection */
114
typedef struct HTTPContext {
115
    enum HTTPState state;
116
    int fd; /* socket file descriptor */
117
    struct sockaddr_in from_addr; /* origin */
118
    struct pollfd *poll_entry; /* used when polling */
119 c3f58185 Alex Beregszaszi
    int64_t timeout;
120 0c1a9eda Zdenek Kabelac
    uint8_t *buffer_ptr, *buffer_end;
121 85f07f22 Fabrice Bellard
    int http_error;
122 edfdd798 Alex Beregszaszi
    int post;
123 19c8c4ec Ronald S. Bultje
    int chunked_encoding;
124
    int chunk_size;               /* 0 if it needs to be read */
125 85f07f22 Fabrice Bellard
    struct HTTPContext *next;
126 42a63c6a Philip Gladstone
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
127 0c1a9eda Zdenek Kabelac
    int64_t data_count;
128 85f07f22 Fabrice Bellard
    /* feed input */
129
    int feed_fd;
130
    /* input format handling */
131
    AVFormatContext *fmt_in;
132 c3f58185 Alex Beregszaszi
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
133 0c1a9eda Zdenek Kabelac
    int64_t first_pts;            /* initial pts value */
134 e240a0bb Fabrice Bellard
    int64_t cur_pts;             /* current pts value from the stream in us */
135
    int64_t cur_frame_duration;  /* duration of the current frame in us */
136
    int cur_frame_bytes;       /* output frame size, needed to compute
137
                                  the time at which we send each
138
                                  packet */
139
    int pts_stream_index;        /* stream we choose as clock reference */
140
    int64_t cur_clock;           /* current clock reference value in us */
141 85f07f22 Fabrice Bellard
    /* output format handling */
142
    struct FFStream *stream;
143 cde25790 Philip Gladstone
    /* -1 is invalid stream */
144
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
145
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
146
    int switch_pending;
147 2effd274 Fabrice Bellard
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
148 85f07f22 Fabrice Bellard
    int last_packet_sent; /* true if last data packet was sent */
149 7434ba6d Philip Gladstone
    int suppress_log;
150 5eb765ef Philip Gladstone
    DataRateData datarate;
151 3120d2a2 Philip Gladstone
    int wmp_client_id;
152 7434ba6d Philip Gladstone
    char protocol[16];
153
    char method[16];
154
    char url[128];
155 cde25790 Philip Gladstone
    int buffer_size;
156 0c1a9eda Zdenek Kabelac
    uint8_t *buffer;
157 2effd274 Fabrice Bellard
    int is_packetized; /* if true, the stream is packetized */
158
    int packet_stream_index; /* current stream for output in state machine */
159 115329f1 Diego Biurrun
160 2effd274 Fabrice Bellard
    /* RTSP state specific */
161 0c1a9eda Zdenek Kabelac
    uint8_t *pb_buffer; /* XXX: use that in all the code */
162 2effd274 Fabrice Bellard
    ByteIOContext *pb;
163
    int seq; /* RTSP sequence number */
164 115329f1 Diego Biurrun
165 2effd274 Fabrice Bellard
    /* RTP state specific */
166 90abbdba Ronald S. Bultje
    enum RTSPLowerTransport rtp_protocol;
167 2effd274 Fabrice Bellard
    char session_id[32]; /* session id */
168
    AVFormatContext *rtp_ctx[MAX_STREAMS];
169 e240a0bb Fabrice Bellard
170 bc351386 Fabrice Bellard
    /* RTP/UDP specific */
171
    URLContext *rtp_handles[MAX_STREAMS];
172
173
    /* RTP/TCP specific */
174
    struct HTTPContext *rtsp_c;
175
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
176 85f07f22 Fabrice Bellard
} HTTPContext;
177
178
/* each generated stream is described here */
179
enum StreamType {
180
    STREAM_TYPE_LIVE,
181
    STREAM_TYPE_STATUS,
182 cde25790 Philip Gladstone
    STREAM_TYPE_REDIRECT,
183 85f07f22 Fabrice Bellard
};
184
185 8256c0a3 Philip Gladstone
enum IPAddressAction {
186
    IP_ALLOW = 1,
187
    IP_DENY,
188
};
189
190
typedef struct IPAddressACL {
191
    struct IPAddressACL *next;
192
    enum IPAddressAction action;
193 efa04ce2 Philip Gladstone
    /* These are in host order */
194 8256c0a3 Philip Gladstone
    struct in_addr first;
195
    struct in_addr last;
196
} IPAddressACL;
197
198 85f07f22 Fabrice Bellard
/* description of each stream of the ffserver.conf file */
199
typedef struct FFStream {
200
    enum StreamType stream_type;
201
    char filename[1024];     /* stream filename */
202 2effd274 Fabrice Bellard
    struct FFStream *feed;   /* feed we are using (can be null if
203
                                coming from file) */
204 e240a0bb Fabrice Bellard
    AVFormatParameters *ap_in; /* input parameters */
205
    AVInputFormat *ifmt;       /* if non NULL, force input format */
206 bd7cf6ad Fabrice Bellard
    AVOutputFormat *fmt;
207 8256c0a3 Philip Gladstone
    IPAddressACL *acl;
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 5a635bc7 Stefano Sabatini
static const char *config_filename;
297 2ac887ba Philip Gladstone
static int ffserver_debug;
298 2effd274 Fabrice Bellard
static int ffserver_daemon;
299 2ac887ba Philip Gladstone
static int no_launch;
300 5eb765ef Philip Gladstone
static int need_to_start_children;
301 2ac887ba Philip Gladstone
302 1c9ff179 Stefano Sabatini
/* maximum number of simultaneous HTTP connections */
303
static unsigned int nb_max_http_connections = 2000;
304 4af92de6 Stefano Sabatini
static unsigned int nb_max_connections = 5;
305
static unsigned int nb_connections;
306 85f07f22 Fabrice Bellard
307 f69bb0cc Baptiste Coudurier
static uint64_t max_bandwidth = 1000;
308 1ad8289e Baptiste Coudurier
static uint64_t current_bandwidth;
309 42a63c6a Philip Gladstone
310 c3f58185 Alex Beregszaszi
static int64_t cur_time;           // Making this global saves on passing it around everywhere
311 5eb765ef Philip Gladstone
312 042819c5 Baptiste Coudurier
static AVLFG random_state;
313 1df93ae9 Alex Beregszaszi
314 85f07f22 Fabrice Bellard
static FILE *logfile = NULL;
315
316 9fd3442f Baptiste Coudurier
static char *ctime1(char *buf2)
317
{
318
    time_t ti;
319
    char *p;
320
321
    ti = time(NULL);
322
    p = ctime(&ti);
323
    strcpy(buf2, p);
324
    p = buf2 + strlen(p) - 1;
325
    if (*p == '\n')
326
        *p = '\0';
327
    return buf2;
328
}
329
330 bcd3ce59 Baptiste Coudurier
static void http_vlog(const char *fmt, va_list vargs)
331 85f07f22 Fabrice Bellard
{
332 124ed1c0 Baptiste Coudurier
    static int print_prefix = 1;
333 7434ba6d Philip Gladstone
    if (logfile) {
334 124ed1c0 Baptiste Coudurier
        if (print_prefix) {
335 9fd3442f Baptiste Coudurier
            char buf[32];
336
            ctime1(buf);
337
            fprintf(logfile, "%s ", buf);
338 124ed1c0 Baptiste Coudurier
        }
339
        print_prefix = strstr(fmt, "\n") != NULL;
340 bcd3ce59 Baptiste Coudurier
        vfprintf(logfile, fmt, vargs);
341 7434ba6d Philip Gladstone
        fflush(logfile);
342
    }
343 bcd3ce59 Baptiste Coudurier
}
344
345 7f6a384a Diego Biurrun
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
346 bcd3ce59 Baptiste Coudurier
{
347
    va_list vargs;
348
    va_start(vargs, fmt);
349
    http_vlog(fmt, vargs);
350
    va_end(vargs);
351
}
352
353
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
354
{
355
    static int print_prefix = 1;
356
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
357 49ceb58b Michael Niedermayer
    if (level > av_log_get_level())
358 bcd3ce59 Baptiste Coudurier
        return;
359
    if (print_prefix && avc)
360 59e7894c Baptiste Coudurier
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
361 bcd3ce59 Baptiste Coudurier
    print_prefix = strstr(fmt, "\n") != NULL;
362
    http_vlog(fmt, vargs);
363 85f07f22 Fabrice Bellard
}
364
365 6edd6884 Fabrice Bellard
static void log_connection(HTTPContext *c)
366
{
367 115329f1 Diego Biurrun
    if (c->suppress_log)
368 6edd6884 Fabrice Bellard
        return;
369
370 82e0be62 Baptiste Coudurier
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
371
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
372 6edd6884 Fabrice Bellard
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
373 cde25790 Philip Gladstone
}
374
375 0c1a9eda Zdenek Kabelac
static void update_datarate(DataRateData *drd, int64_t count)
376 5eb765ef Philip Gladstone
{
377
    if (!drd->time1 && !drd->count1) {
378
        drd->time1 = drd->time2 = cur_time;
379
        drd->count1 = drd->count2 = count;
380 eeffbdea Alex Beregszaszi
    } else if (cur_time - drd->time2 > 5000) {
381 33a4ecbe Alex Beregszaszi
        drd->time1 = drd->time2;
382
        drd->count1 = drd->count2;
383
        drd->time2 = cur_time;
384
        drd->count2 = count;
385 5eb765ef Philip Gladstone
    }
386
}
387
388
/* In bytes per second */
389 0c1a9eda Zdenek Kabelac
static int compute_datarate(DataRateData *drd, int64_t count)
390 5eb765ef Philip Gladstone
{
391
    if (cur_time == drd->time1)
392
        return 0;
393 115329f1 Diego Biurrun
394 5eb765ef Philip Gladstone
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
395
}
396
397 a782f209 Philip Gladstone
398 cde25790 Philip Gladstone
static void start_children(FFStream *feed)
399
{
400 2ac887ba Philip Gladstone
    if (no_launch)
401
        return;
402
403 cde25790 Philip Gladstone
    for (; feed; feed = feed->next) {
404 5eb765ef Philip Gladstone
        if (feed->child_argv && !feed->pid) {
405
            feed->pid_start = time(0);
406
407 cde25790 Philip Gladstone
            feed->pid = fork();
408
409
            if (feed->pid < 0) {
410 b4befb99 Baptiste Coudurier
                http_log("Unable to create children\n");
411 cde25790 Philip Gladstone
                exit(1);
412
            }
413
            if (!feed->pid) {
414
                /* In child */
415
                char pathname[1024];
416
                char *slash;
417
                int i;
418
419 40444a59 Stefano Sabatini
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
420
421
                slash = strrchr(pathname, '/');
422
                if (!slash)
423
                    slash = pathname;
424
                else
425
                    slash++;
426
                strcpy(slash, "ffmpeg");
427
428 8bf61f5b Stefano Sabatini
                http_log("Launch commandline: ");
429
                http_log("%s ", pathname);
430
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
431
                    http_log("%s ", feed->child_argv[i]);
432
                http_log("\n");
433 40444a59 Stefano Sabatini
434 611c5741 Alex Beregszaszi
                for (i = 3; i < 256; i++)
435 5eb765ef Philip Gladstone
                    close(i);
436 cde25790 Philip Gladstone
437 5eb765ef Philip Gladstone
                if (!ffserver_debug) {
438 2ac887ba Philip Gladstone
                    i = open("/dev/null", O_RDWR);
439 3296409d Baptiste Coudurier
                    if (i != -1) {
440 2ac887ba Philip Gladstone
                        dup2(i, 0);
441 3296409d Baptiste Coudurier
                        dup2(i, 1);
442
                        dup2(i, 2);
443 5eb765ef Philip Gladstone
                        close(i);
444 3296409d Baptiste Coudurier
                    }
445 2ac887ba Philip Gladstone
                }
446 cde25790 Philip Gladstone
447 d6562d2c Philip Gladstone
                /* This is needed to make relative pathnames work */
448
                chdir(my_program_dir);
449
450 a4d70941 Philip Gladstone
                signal(SIGPIPE, SIG_DFL);
451
452 cde25790 Philip Gladstone
                execvp(pathname, feed->child_argv);
453
454
                _exit(1);
455
            }
456
        }
457
    }
458 7434ba6d Philip Gladstone
}
459
460 2effd274 Fabrice Bellard
/* open a listening socket */
461
static int socket_open_listen(struct sockaddr_in *my_addr)
462 85f07f22 Fabrice Bellard
{
463 2effd274 Fabrice Bellard
    int server_fd, tmp;
464 85f07f22 Fabrice Bellard
465
    server_fd = socket(AF_INET,SOCK_STREAM,0);
466
    if (server_fd < 0) {
467
        perror ("socket");
468
        return -1;
469
    }
470 115329f1 Diego Biurrun
471 85f07f22 Fabrice Bellard
    tmp = 1;
472
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
473
474 2effd274 Fabrice Bellard
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
475 b17d099d Philip Gladstone
        char bindmsg[32];
476
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
477
        perror (bindmsg);
478 d96633bb Alex Beregszaszi
        closesocket(server_fd);
479 85f07f22 Fabrice Bellard
        return -1;
480
    }
481 115329f1 Diego Biurrun
482 85f07f22 Fabrice Bellard
    if (listen (server_fd, 5) < 0) {
483
        perror ("listen");
484 d96633bb Alex Beregszaszi
        closesocket(server_fd);
485 85f07f22 Fabrice Bellard
        return -1;
486
    }
487 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(server_fd, 1);
488 2effd274 Fabrice Bellard
489
    return server_fd;
490
}
491
492 6edd6884 Fabrice Bellard
/* start all multicast streams */
493
static void start_multicast(void)
494
{
495
    FFStream *stream;
496
    char session_id[32];
497
    HTTPContext *rtp_c;
498
    struct sockaddr_in dest_addr;
499
    int default_port, stream_index;
500
501
    default_port = 6000;
502
    for(stream = first_stream; stream != NULL; stream = stream->next) {
503
        if (stream->is_multicast) {
504
            /* open the RTP connection */
505 1df93ae9 Alex Beregszaszi
            snprintf(session_id, sizeof(session_id), "%08x%08x",
506 042819c5 Baptiste Coudurier
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
507 6edd6884 Fabrice Bellard
508
            /* choose a port if none given */
509
            if (stream->multicast_port == 0) {
510
                stream->multicast_port = default_port;
511
                default_port += 100;
512
            }
513
514
            dest_addr.sin_family = AF_INET;
515
            dest_addr.sin_addr = stream->multicast_ip;
516
            dest_addr.sin_port = htons(stream->multicast_port);
517
518 115329f1 Diego Biurrun
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
519 90abbdba Ronald S. Bultje
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
520 611c5741 Alex Beregszaszi
            if (!rtp_c)
521 6edd6884 Fabrice Bellard
                continue;
522 611c5741 Alex Beregszaszi
523 6edd6884 Fabrice Bellard
            if (open_input_stream(rtp_c, "") < 0) {
524 b4befb99 Baptiste Coudurier
                http_log("Could not open input stream for stream '%s'\n",
525
                         stream->filename);
526 6edd6884 Fabrice Bellard
                continue;
527
            }
528
529
            /* open each RTP stream */
530 115329f1 Diego Biurrun
            for(stream_index = 0; stream_index < stream->nb_streams;
531 6edd6884 Fabrice Bellard
                stream_index++) {
532 115329f1 Diego Biurrun
                dest_addr.sin_port = htons(stream->multicast_port +
533 6edd6884 Fabrice Bellard
                                           2 * stream_index);
534 bc351386 Fabrice Bellard
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
535 b4befb99 Baptiste Coudurier
                    http_log("Could not open output stream '%s/streamid=%d'\n",
536
                             stream->filename, stream_index);
537 0fa45e19 Fabrice Bellard
                    exit(1);
538 6edd6884 Fabrice Bellard
                }
539
            }
540
541
            /* change state to send data */
542
            rtp_c->state = HTTPSTATE_SEND_DATA;
543
        }
544
    }
545
}
546 2effd274 Fabrice Bellard
547
/* main loop of the http server */
548
static int http_server(void)
549
{
550 d2a1ea1d Baptiste Coudurier
    int server_fd = 0, rtsp_server_fd = 0;
551
    int ret, delay, delay1;
552 1c9ff179 Stefano Sabatini
    struct pollfd *poll_table, *poll_entry;
553 2effd274 Fabrice Bellard
    HTTPContext *c, *c_next;
554
555 a7f361eb Baptiste Coudurier
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
556 1c9ff179 Stefano Sabatini
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
557
        return -1;
558
    }
559
560 d2a1ea1d Baptiste Coudurier
    if (my_http_addr.sin_port) {
561 2b9cd1e7 Baptiste Coudurier
        server_fd = socket_open_listen(&my_http_addr);
562
        if (server_fd < 0)
563
            return -1;
564 d2a1ea1d Baptiste Coudurier
    }
565 85f07f22 Fabrice Bellard
566 d2a1ea1d Baptiste Coudurier
    if (my_rtsp_addr.sin_port) {
567 2b9cd1e7 Baptiste Coudurier
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
568
        if (rtsp_server_fd < 0)
569
            return -1;
570 d2a1ea1d Baptiste Coudurier
    }
571
572
    if (!rtsp_server_fd && !server_fd) {
573
        http_log("HTTP and RTSP disabled.\n");
574
        return -1;
575
    }
576 115329f1 Diego Biurrun
577 a3341b9d Baptiste Coudurier
    http_log("FFserver started.\n");
578 85f07f22 Fabrice Bellard
579 cde25790 Philip Gladstone
    start_children(first_feed);
580
581 6edd6884 Fabrice Bellard
    start_multicast();
582
583 85f07f22 Fabrice Bellard
    for(;;) {
584
        poll_entry = poll_table;
585 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
586 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = server_fd;
587
            poll_entry->events = POLLIN;
588
            poll_entry++;
589 d2a1ea1d Baptiste Coudurier
        }
590
        if (rtsp_server_fd) {
591 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = rtsp_server_fd;
592
            poll_entry->events = POLLIN;
593
            poll_entry++;
594 d2a1ea1d Baptiste Coudurier
        }
595 2effd274 Fabrice Bellard
596 85f07f22 Fabrice Bellard
        /* wait for events on each HTTP handle */
597
        c = first_http_ctx;
598 2effd274 Fabrice Bellard
        delay = 1000;
599 85f07f22 Fabrice Bellard
        while (c != NULL) {
600
            int fd;
601
            fd = c->fd;
602
            switch(c->state) {
603 2effd274 Fabrice Bellard
            case HTTPSTATE_SEND_HEADER:
604
            case RTSPSTATE_SEND_REPLY:
605 bc351386 Fabrice Bellard
            case RTSPSTATE_SEND_PACKET:
606 85f07f22 Fabrice Bellard
                c->poll_entry = poll_entry;
607
                poll_entry->fd = fd;
608 2effd274 Fabrice Bellard
                poll_entry->events = POLLOUT;
609 85f07f22 Fabrice Bellard
                poll_entry++;
610
                break;
611
            case HTTPSTATE_SEND_DATA_HEADER:
612
            case HTTPSTATE_SEND_DATA:
613
            case HTTPSTATE_SEND_DATA_TRAILER:
614 2effd274 Fabrice Bellard
                if (!c->is_packetized) {
615
                    /* for TCP, we output as much as we can (may need to put a limit) */
616
                    c->poll_entry = poll_entry;
617
                    poll_entry->fd = fd;
618
                    poll_entry->events = POLLOUT;
619
                    poll_entry++;
620
                } else {
621 e240a0bb Fabrice Bellard
                    /* when ffserver is doing the timing, we work by
622
                       looking at which packet need to be sent every
623
                       10 ms */
624
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
625
                    if (delay1 < delay)
626
                        delay = delay1;
627 2effd274 Fabrice Bellard
                }
628 85f07f22 Fabrice Bellard
                break;
629 2effd274 Fabrice Bellard
            case HTTPSTATE_WAIT_REQUEST:
630 85f07f22 Fabrice Bellard
            case HTTPSTATE_RECEIVE_DATA:
631
            case HTTPSTATE_WAIT_FEED:
632 2effd274 Fabrice Bellard
            case RTSPSTATE_WAIT_REQUEST:
633 85f07f22 Fabrice Bellard
                /* need to catch errors */
634
                c->poll_entry = poll_entry;
635
                poll_entry->fd = fd;
636 a6e14edd Philip Gladstone
                poll_entry->events = POLLIN;/* Maybe this will work */
637 85f07f22 Fabrice Bellard
                poll_entry++;
638
                break;
639
            default:
640
                c->poll_entry = NULL;
641
                break;
642
            }
643
            c = c->next;
644
        }
645
646
        /* wait for an event on one connection. We poll at least every
647
           second to handle timeouts */
648
        do {
649 2effd274 Fabrice Bellard
            ret = poll(poll_table, poll_entry - poll_table, delay);
650 8da4034f Alex Beregszaszi
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
651
                ff_neterrno() != FF_NETERROR(EINTR))
652 53e2f9ca Michael Niedermayer
                return -1;
653 e8d658df Luca Abeni
        } while (ret < 0);
654 115329f1 Diego Biurrun
655 c3f58185 Alex Beregszaszi
        cur_time = av_gettime() / 1000;
656 85f07f22 Fabrice Bellard
657 5eb765ef Philip Gladstone
        if (need_to_start_children) {
658
            need_to_start_children = 0;
659
            start_children(first_feed);
660
        }
661
662 85f07f22 Fabrice Bellard
        /* now handle the events */
663 2effd274 Fabrice Bellard
        for(c = first_http_ctx; c != NULL; c = c_next) {
664
            c_next = c->next;
665
            if (handle_connection(c) < 0) {
666 85f07f22 Fabrice Bellard
                /* close and free the connection */
667 7434ba6d Philip Gladstone
                log_connection(c);
668 2effd274 Fabrice Bellard
                close_connection(c);
669 85f07f22 Fabrice Bellard
            }
670
        }
671
672
        poll_entry = poll_table;
673 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
674 2b9cd1e7 Baptiste Coudurier
            /* new HTTP connection request ? */
675
            if (poll_entry->revents & POLLIN)
676
                new_connection(server_fd, 0);
677
            poll_entry++;
678 d2a1ea1d Baptiste Coudurier
        }
679
        if (rtsp_server_fd) {
680 2b9cd1e7 Baptiste Coudurier
            /* new RTSP connection request ? */
681
            if (poll_entry->revents & POLLIN)
682
                new_connection(rtsp_server_fd, 1);
683 d2a1ea1d Baptiste Coudurier
        }
684 85f07f22 Fabrice Bellard
    }
685
}
686
687 2effd274 Fabrice Bellard
/* start waiting for a new HTTP/RTSP request */
688
static void start_wait_request(HTTPContext *c, int is_rtsp)
689 85f07f22 Fabrice Bellard
{
690 2effd274 Fabrice Bellard
    c->buffer_ptr = c->buffer;
691
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
692
693
    if (is_rtsp) {
694
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
695
        c->state = RTSPSTATE_WAIT_REQUEST;
696
    } else {
697
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
698
        c->state = HTTPSTATE_WAIT_REQUEST;
699
    }
700
}
701
702 0bdd8b85 Baptiste Coudurier
static void http_send_too_busy_reply(int fd)
703
{
704
    char buffer[300];
705
    int len = snprintf(buffer, sizeof(buffer),
706
                       "HTTP/1.0 200 Server too busy\r\n"
707
                       "Content-type: text/html\r\n"
708
                       "\r\n"
709
                       "<html><head><title>Too busy</title></head><body>\r\n"
710
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
711
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
712
                       "</body></html>\r\n",
713
                       nb_connections, nb_max_connections);
714
    send(fd, buffer, len, 0);
715
}
716
717
718 2effd274 Fabrice Bellard
static void new_connection(int server_fd, int is_rtsp)
719
{
720
    struct sockaddr_in from_addr;
721
    int fd, len;
722
    HTTPContext *c = NULL;
723
724
    len = sizeof(from_addr);
725 115329f1 Diego Biurrun
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
726 2effd274 Fabrice Bellard
                &len);
727 050056d0 Baptiste Coudurier
    if (fd < 0) {
728
        http_log("error during accept %s\n", strerror(errno));
729 2effd274 Fabrice Bellard
        return;
730 050056d0 Baptiste Coudurier
    }
731 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(fd, 1);
732 2effd274 Fabrice Bellard
733 0bdd8b85 Baptiste Coudurier
    if (nb_connections >= nb_max_connections) {
734
        http_send_too_busy_reply(fd);
735 2effd274 Fabrice Bellard
        goto fail;
736 0bdd8b85 Baptiste Coudurier
    }
737 115329f1 Diego Biurrun
738 2effd274 Fabrice Bellard
    /* add a new connection */
739
    c = av_mallocz(sizeof(HTTPContext));
740
    if (!c)
741
        goto fail;
742 115329f1 Diego Biurrun
743 2effd274 Fabrice Bellard
    c->fd = fd;
744
    c->poll_entry = NULL;
745
    c->from_addr = from_addr;
746
    c->buffer_size = IOBUFFER_INIT_SIZE;
747
    c->buffer = av_malloc(c->buffer_size);
748
    if (!c->buffer)
749
        goto fail;
750 8bc80f8b Philip Gladstone
751
    c->next = first_http_ctx;
752
    first_http_ctx = c;
753 2effd274 Fabrice Bellard
    nb_connections++;
754 115329f1 Diego Biurrun
755 2effd274 Fabrice Bellard
    start_wait_request(c, is_rtsp);
756
757
    return;
758
759
 fail:
760
    if (c) {
761
        av_free(c->buffer);
762
        av_free(c);
763
    }
764 d96633bb Alex Beregszaszi
    closesocket(fd);
765 2effd274 Fabrice Bellard
}
766
767
static void close_connection(HTTPContext *c)
768
{
769
    HTTPContext **cp, *c1;
770
    int i, nb_streams;
771
    AVFormatContext *ctx;
772
    URLContext *h;
773
    AVStream *st;
774
775
    /* remove connection from list */
776
    cp = &first_http_ctx;
777
    while ((*cp) != NULL) {
778
        c1 = *cp;
779 611c5741 Alex Beregszaszi
        if (c1 == c)
780 2effd274 Fabrice Bellard
            *cp = c->next;
781 611c5741 Alex Beregszaszi
        else
782 2effd274 Fabrice Bellard
            cp = &c1->next;
783
    }
784
785 bc351386 Fabrice Bellard
    /* remove references, if any (XXX: do it faster) */
786
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
787
        if (c1->rtsp_c == c)
788
            c1->rtsp_c = NULL;
789
    }
790
791 2effd274 Fabrice Bellard
    /* remove connection associated resources */
792
    if (c->fd >= 0)
793 d96633bb Alex Beregszaszi
        closesocket(c->fd);
794 2effd274 Fabrice Bellard
    if (c->fmt_in) {
795
        /* close each frame parser */
796
        for(i=0;i<c->fmt_in->nb_streams;i++) {
797
            st = c->fmt_in->streams[i];
798 611c5741 Alex Beregszaszi
            if (st->codec->codec)
799 01f4895c Michael Niedermayer
                avcodec_close(st->codec);
800 2effd274 Fabrice Bellard
        }
801
        av_close_input_file(c->fmt_in);
802
    }
803
804
    /* free RTP output streams if any */
805
    nb_streams = 0;
806 115329f1 Diego Biurrun
    if (c->stream)
807 2effd274 Fabrice Bellard
        nb_streams = c->stream->nb_streams;
808 115329f1 Diego Biurrun
809 2effd274 Fabrice Bellard
    for(i=0;i<nb_streams;i++) {
810
        ctx = c->rtp_ctx[i];
811
        if (ctx) {
812
            av_write_trailer(ctx);
813
            av_free(ctx);
814
        }
815
        h = c->rtp_handles[i];
816 611c5741 Alex Beregszaszi
        if (h)
817 2effd274 Fabrice Bellard
            url_close(h);
818
    }
819 115329f1 Diego Biurrun
820 b88ba823 Mark Hills
    ctx = &c->fmt_ctx;
821
822 637b638e Baptiste Coudurier
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
823 87638494 Philip Gladstone
        if (ctx->oformat) {
824
            /* prepare header */
825
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
826
                av_write_trailer(ctx);
827 f8b06be9 Baptiste Coudurier
                av_freep(&c->pb_buffer);
828 899681cd Björn Axelsson
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
829 87638494 Philip Gladstone
            }
830
        }
831
    }
832
833 115329f1 Diego Biurrun
    for(i=0; i<ctx->nb_streams; i++)
834 0bd53967 Alex Beregszaszi
        av_free(ctx->streams[i]);
835 f0ef6240 Philip Gladstone
836 edfdd798 Alex Beregszaszi
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
837 6edd6884 Fabrice Bellard
        current_bandwidth -= c->stream->bandwidth;
838 5400e092 Alex Beregszaszi
839
    /* signal that there is no feed if we are the feeder socket */
840
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
841
        c->stream->feed_opened = 0;
842
        close(c->feed_fd);
843
    }
844
845 2effd274 Fabrice Bellard
    av_freep(&c->pb_buffer);
846 bc351386 Fabrice Bellard
    av_freep(&c->packet_buffer);
847 2effd274 Fabrice Bellard
    av_free(c->buffer);
848
    av_free(c);
849
    nb_connections--;
850
}
851
852
static int handle_connection(HTTPContext *c)
853
{
854
    int len, ret;
855 115329f1 Diego Biurrun
856 85f07f22 Fabrice Bellard
    switch(c->state) {
857
    case HTTPSTATE_WAIT_REQUEST:
858 2effd274 Fabrice Bellard
    case RTSPSTATE_WAIT_REQUEST:
859 85f07f22 Fabrice Bellard
        /* timeout ? */
860
        if ((c->timeout - cur_time) < 0)
861
            return -1;
862
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
863
            return -1;
864
865
        /* no need to read if no events */
866
        if (!(c->poll_entry->revents & POLLIN))
867
            return 0;
868
        /* read the data */
869 1bc1cfdd Giancarlo Formicuccia
    read_loop:
870 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, 1, 0);
871 85f07f22 Fabrice Bellard
        if (len < 0) {
872 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
873
                ff_neterrno() != FF_NETERROR(EINTR))
874 85f07f22 Fabrice Bellard
                return -1;
875
        } else if (len == 0) {
876
            return -1;
877
        } else {
878 94d9ad5f Giancarlo Formicuccia
            /* search for end of request. */
879 0c1a9eda Zdenek Kabelac
            uint8_t *ptr;
880 85f07f22 Fabrice Bellard
            c->buffer_ptr += len;
881
            ptr = c->buffer_ptr;
882
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
883
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
884
                /* request found : parse it and reply */
885 2effd274 Fabrice Bellard
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
886
                    ret = http_parse_request(c);
887
                } else {
888
                    ret = rtsp_parse_request(c);
889
                }
890
                if (ret < 0)
891 85f07f22 Fabrice Bellard
                    return -1;
892
            } else if (ptr >= c->buffer_end) {
893
                /* request too long: cannot do anything */
894
                return -1;
895 1bc1cfdd Giancarlo Formicuccia
            } else goto read_loop;
896 85f07f22 Fabrice Bellard
        }
897
        break;
898
899
    case HTTPSTATE_SEND_HEADER:
900
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
901
            return -1;
902
903 2effd274 Fabrice Bellard
        /* no need to write if no events */
904 85f07f22 Fabrice Bellard
        if (!(c->poll_entry->revents & POLLOUT))
905
            return 0;
906 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
907 85f07f22 Fabrice Bellard
        if (len < 0) {
908 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
909
                ff_neterrno() != FF_NETERROR(EINTR)) {
910 85f07f22 Fabrice Bellard
                /* error : close connection */
911 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
912 85f07f22 Fabrice Bellard
                return -1;
913
            }
914
        } else {
915
            c->buffer_ptr += len;
916 2e04edb3 Philip Gladstone
            if (c->stream)
917
                c->stream->bytes_served += len;
918 a6e14edd Philip Gladstone
            c->data_count += len;
919 85f07f22 Fabrice Bellard
            if (c->buffer_ptr >= c->buffer_end) {
920 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
921 85f07f22 Fabrice Bellard
                /* if error, exit */
922 611c5741 Alex Beregszaszi
                if (c->http_error)
923 85f07f22 Fabrice Bellard
                    return -1;
924 2effd274 Fabrice Bellard
                /* all the buffer was sent : synchronize to the incoming stream */
925 85f07f22 Fabrice Bellard
                c->state = HTTPSTATE_SEND_DATA_HEADER;
926
                c->buffer_ptr = c->buffer_end = c->buffer;
927
            }
928
        }
929
        break;
930
931
    case HTTPSTATE_SEND_DATA:
932
    case HTTPSTATE_SEND_DATA_HEADER:
933
    case HTTPSTATE_SEND_DATA_TRAILER:
934 2effd274 Fabrice Bellard
        /* for packetized output, we consider we can always write (the
935
           input streams sets the speed). It may be better to verify
936
           that we do not rely too much on the kernel queues */
937
        if (!c->is_packetized) {
938
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
939
                return -1;
940 115329f1 Diego Biurrun
941 2effd274 Fabrice Bellard
            /* no need to read if no events */
942
            if (!(c->poll_entry->revents & POLLOUT))
943
                return 0;
944
        }
945 5eb765ef Philip Gladstone
        if (http_send_data(c) < 0)
946 85f07f22 Fabrice Bellard
            return -1;
947 638831aa Alex Beregszaszi
        /* close connection if trailer sent */
948
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
949
            return -1;
950 85f07f22 Fabrice Bellard
        break;
951
    case HTTPSTATE_RECEIVE_DATA:
952
        /* no need to read if no events */
953
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
954
            return -1;
955
        if (!(c->poll_entry->revents & POLLIN))
956
            return 0;
957
        if (http_receive_data(c) < 0)
958
            return -1;
959
        break;
960
    case HTTPSTATE_WAIT_FEED:
961
        /* no need to read if no events */
962 a6e14edd Philip Gladstone
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
963 85f07f22 Fabrice Bellard
            return -1;
964
965
        /* nothing to do, we'll be waken up by incoming feed packets */
966
        break;
967 2effd274 Fabrice Bellard
968
    case RTSPSTATE_SEND_REPLY:
969
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
970
            av_freep(&c->pb_buffer);
971
            return -1;
972
        }
973
        /* no need to write if no events */
974
        if (!(c->poll_entry->revents & POLLOUT))
975
            return 0;
976 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
977 2effd274 Fabrice Bellard
        if (len < 0) {
978 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
979
                ff_neterrno() != FF_NETERROR(EINTR)) {
980 2effd274 Fabrice Bellard
                /* error : close connection */
981
                av_freep(&c->pb_buffer);
982
                return -1;
983
            }
984
        } else {
985
            c->buffer_ptr += len;
986
            c->data_count += len;
987
            if (c->buffer_ptr >= c->buffer_end) {
988
                /* all the buffer was sent : wait for a new request */
989
                av_freep(&c->pb_buffer);
990
                start_wait_request(c, 1);
991
            }
992
        }
993
        break;
994 bc351386 Fabrice Bellard
    case RTSPSTATE_SEND_PACKET:
995
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
996
            av_freep(&c->packet_buffer);
997
            return -1;
998
        }
999
        /* no need to write if no events */
1000
        if (!(c->poll_entry->revents & POLLOUT))
1001
            return 0;
1002 c60202df Alex Beregszaszi
        len = send(c->fd, c->packet_buffer_ptr,
1003
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1004 bc351386 Fabrice Bellard
        if (len < 0) {
1005 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1006
                ff_neterrno() != FF_NETERROR(EINTR)) {
1007 bc351386 Fabrice Bellard
                /* error : close connection */
1008
                av_freep(&c->packet_buffer);
1009
                return -1;
1010
            }
1011
        } else {
1012
            c->packet_buffer_ptr += len;
1013
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1014
                /* all the buffer was sent : wait for a new request */
1015
                av_freep(&c->packet_buffer);
1016
                c->state = RTSPSTATE_WAIT_REQUEST;
1017
            }
1018
        }
1019
        break;
1020 2effd274 Fabrice Bellard
    case HTTPSTATE_READY:
1021
        /* nothing to do */
1022
        break;
1023 85f07f22 Fabrice Bellard
    default:
1024
        return -1;
1025
    }
1026
    return 0;
1027
}
1028
1029 3120d2a2 Philip Gladstone
static int extract_rates(char *rates, int ratelen, const char *request)
1030
{
1031
    const char *p;
1032
1033
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1034
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1035
            const char *q = p + 7;
1036
1037
            while (*q && *q != '\n' && isspace(*q))
1038
                q++;
1039
1040
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1041
                int stream_no;
1042
                int rate_no;
1043
1044
                q += 20;
1045
1046 cde25790 Philip Gladstone
                memset(rates, 0xff, ratelen);
1047 3120d2a2 Philip Gladstone
1048
                while (1) {
1049
                    while (*q && *q != '\n' && *q != ':')
1050
                        q++;
1051
1052 611c5741 Alex Beregszaszi
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1053 3120d2a2 Philip Gladstone
                        break;
1054 611c5741 Alex Beregszaszi
1055 3120d2a2 Philip Gladstone
                    stream_no--;
1056 611c5741 Alex Beregszaszi
                    if (stream_no < ratelen && stream_no >= 0)
1057 3120d2a2 Philip Gladstone
                        rates[stream_no] = rate_no;
1058
1059
                    while (*q && *q != '\n' && !isspace(*q))
1060
                        q++;
1061
                }
1062
1063
                return 1;
1064
            }
1065
        }
1066
        p = strchr(p, '\n');
1067
        if (!p)
1068
            break;
1069
1070
        p++;
1071
    }
1072
1073
    return 0;
1074
}
1075
1076 cde25790 Philip Gladstone
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1077 3120d2a2 Philip Gladstone
{
1078
    int i;
1079 cde25790 Philip Gladstone
    int best_bitrate = 100000000;
1080
    int best = -1;
1081
1082
    for (i = 0; i < feed->nb_streams; i++) {
1083 01f4895c Michael Niedermayer
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1084 cde25790 Philip Gladstone
1085
        if (feed_codec->codec_id != codec->codec_id ||
1086
            feed_codec->sample_rate != codec->sample_rate ||
1087
            feed_codec->width != codec->width ||
1088 611c5741 Alex Beregszaszi
            feed_codec->height != codec->height)
1089 cde25790 Philip Gladstone
            continue;
1090
1091
        /* Potential stream */
1092
1093 115329f1 Diego Biurrun
        /* We want the fastest stream less than bit_rate, or the slowest
1094 cde25790 Philip Gladstone
         * faster than bit_rate
1095
         */
1096
1097
        if (feed_codec->bit_rate <= bit_rate) {
1098
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1099
                best_bitrate = feed_codec->bit_rate;
1100
                best = i;
1101
            }
1102
        } else {
1103
            if (feed_codec->bit_rate < best_bitrate) {
1104
                best_bitrate = feed_codec->bit_rate;
1105
                best = i;
1106
            }
1107
        }
1108
    }
1109
1110
    return best;
1111
}
1112
1113
static int modify_current_stream(HTTPContext *c, char *rates)
1114
{
1115
    int i;
1116
    FFStream *req = c->stream;
1117
    int action_required = 0;
1118 3120d2a2 Philip Gladstone
1119 001bcd29 Philip Gladstone
    /* Not much we can do for a feed */
1120
    if (!req->feed)
1121
        return 0;
1122
1123 3120d2a2 Philip Gladstone
    for (i = 0; i < req->nb_streams; i++) {
1124 01f4895c Michael Niedermayer
        AVCodecContext *codec = req->streams[i]->codec;
1125 3120d2a2 Philip Gladstone
1126
        switch(rates[i]) {
1127
            case 0:
1128 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = req->feed_streams[i];
1129 3120d2a2 Philip Gladstone
                break;
1130
            case 1:
1131 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1132 3120d2a2 Philip Gladstone
                break;
1133
            case 2:
1134 cde25790 Philip Gladstone
                /* Wants off or slow */
1135
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1136
#ifdef WANTS_OFF
1137
                /* This doesn't work well when it turns off the only stream! */
1138
                c->switch_feed_streams[i] = -2;
1139
                c->feed_streams[i] = -2;
1140
#endif
1141 3120d2a2 Philip Gladstone
                break;
1142
        }
1143
1144 cde25790 Philip Gladstone
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1145
            action_required = 1;
1146
    }
1147 3120d2a2 Philip Gladstone
1148 cde25790 Philip Gladstone
    return action_required;
1149
}
1150 3120d2a2 Philip Gladstone
1151
1152 cde25790 Philip Gladstone
static void do_switch_stream(HTTPContext *c, int i)
1153
{
1154
    if (c->switch_feed_streams[i] >= 0) {
1155 115329f1 Diego Biurrun
#ifdef PHILIP
1156 cde25790 Philip Gladstone
        c->feed_streams[i] = c->switch_feed_streams[i];
1157
#endif
1158 3120d2a2 Philip Gladstone
1159 cde25790 Philip Gladstone
        /* Now update the stream */
1160 3120d2a2 Philip Gladstone
    }
1161 cde25790 Philip Gladstone
    c->switch_feed_streams[i] = -1;
1162 3120d2a2 Philip Gladstone
}
1163 7434ba6d Philip Gladstone
1164 2effd274 Fabrice Bellard
/* XXX: factorize in utils.c ? */
1165
/* XXX: take care with different space meaning */
1166
static void skip_spaces(const char **pp)
1167
{
1168
    const char *p;
1169
    p = *pp;
1170
    while (*p == ' ' || *p == '\t')
1171
        p++;
1172
    *pp = p;
1173
}
1174
1175
static void get_word(char *buf, int buf_size, const char **pp)
1176
{
1177
    const char *p;
1178
    char *q;
1179
1180
    p = *pp;
1181
    skip_spaces(&p);
1182
    q = buf;
1183
    while (!isspace(*p) && *p != '\0') {
1184
        if ((q - buf) < buf_size - 1)
1185
            *q++ = *p;
1186
        p++;
1187
    }
1188
    if (buf_size > 0)
1189
        *q = '\0';
1190
    *pp = p;
1191
}
1192
1193 c64c0a9b Benjamin Larsson
static void get_arg(char *buf, int buf_size, const char **pp)
1194
{
1195
    const char *p;
1196
    char *q;
1197
    int quote;
1198
1199
    p = *pp;
1200
    while (isspace(*p)) p++;
1201
    q = buf;
1202
    quote = 0;
1203
    if (*p == '\"' || *p == '\'')
1204
        quote = *p++;
1205
    for(;;) {
1206
        if (quote) {
1207
            if (*p == quote)
1208
                break;
1209
        } else {
1210
            if (isspace(*p))
1211
                break;
1212
        }
1213
        if (*p == '\0')
1214
            break;
1215
        if ((q - buf) < buf_size - 1)
1216
            *q++ = *p;
1217
        p++;
1218
    }
1219
    *q = '\0';
1220
    if (quote && *p == quote)
1221
        p++;
1222
    *pp = p;
1223
}
1224
1225 8256c0a3 Philip Gladstone
static int validate_acl(FFStream *stream, HTTPContext *c)
1226
{
1227
    enum IPAddressAction last_action = IP_DENY;
1228
    IPAddressACL *acl;
1229
    struct in_addr *src = &c->from_addr.sin_addr;
1230 2bd8416e Alex Beregszaszi
    unsigned long src_addr = src->s_addr;
1231 8256c0a3 Philip Gladstone
1232
    for (acl = stream->acl; acl; acl = acl->next) {
1233 611c5741 Alex Beregszaszi
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1234 8256c0a3 Philip Gladstone
            return (acl->action == IP_ALLOW) ? 1 : 0;
1235
        last_action = acl->action;
1236
    }
1237
1238
    /* Nothing matched, so return not the last action */
1239
    return (last_action == IP_DENY) ? 1 : 0;
1240
}
1241
1242 829ac53d Fabrice Bellard
/* compute the real filename of a file by matching it without its
1243
   extensions to all the stream filenames */
1244
static void compute_real_filename(char *filename, int max_size)
1245
{
1246
    char file1[1024];
1247
    char file2[1024];
1248
    char *p;
1249
    FFStream *stream;
1250
1251
    /* compute filename by matching without the file extensions */
1252 f7d78f36 Måns Rullgård
    av_strlcpy(file1, filename, sizeof(file1));
1253 829ac53d Fabrice Bellard
    p = strrchr(file1, '.');
1254
    if (p)
1255
        *p = '\0';
1256
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1257 f7d78f36 Måns Rullgård
        av_strlcpy(file2, stream->filename, sizeof(file2));
1258 829ac53d Fabrice Bellard
        p = strrchr(file2, '.');
1259
        if (p)
1260
            *p = '\0';
1261
        if (!strcmp(file1, file2)) {
1262 f7d78f36 Måns Rullgård
            av_strlcpy(filename, stream->filename, max_size);
1263 829ac53d Fabrice Bellard
            break;
1264
        }
1265
    }
1266
}
1267
1268
enum RedirType {
1269
    REDIR_NONE,
1270
    REDIR_ASX,
1271
    REDIR_RAM,
1272
    REDIR_ASF,
1273
    REDIR_RTSP,
1274
    REDIR_SDP,
1275
};
1276
1277 85f07f22 Fabrice Bellard
/* parse http request and prepare header */
1278
static int http_parse_request(HTTPContext *c)
1279
{
1280
    char *p;
1281 829ac53d Fabrice Bellard
    enum RedirType redir_type;
1282 85f07f22 Fabrice Bellard
    char cmd[32];
1283 bae79c04 Alex Beregszaszi
    char info[1024], filename[1024];
1284 85f07f22 Fabrice Bellard
    char url[1024], *q;
1285
    char protocol[32];
1286
    char msg[1024];
1287
    const char *mime_type;
1288
    FFStream *stream;
1289 42a63c6a Philip Gladstone
    int i;
1290 3120d2a2 Philip Gladstone
    char ratebuf[32];
1291 cde25790 Philip Gladstone
    char *useragent = 0;
1292 85f07f22 Fabrice Bellard
1293
    p = c->buffer;
1294 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), (const char **)&p);
1295 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
1296 7434ba6d Philip Gladstone
1297 85f07f22 Fabrice Bellard
    if (!strcmp(cmd, "GET"))
1298 edfdd798 Alex Beregszaszi
        c->post = 0;
1299 85f07f22 Fabrice Bellard
    else if (!strcmp(cmd, "POST"))
1300 edfdd798 Alex Beregszaszi
        c->post = 1;
1301 85f07f22 Fabrice Bellard
    else
1302
        return -1;
1303
1304 2effd274 Fabrice Bellard
    get_word(url, sizeof(url), (const char **)&p);
1305 f7d78f36 Måns Rullgård
    av_strlcpy(c->url, url, sizeof(c->url));
1306 7434ba6d Philip Gladstone
1307 2effd274 Fabrice Bellard
    get_word(protocol, sizeof(protocol), (const char **)&p);
1308 85f07f22 Fabrice Bellard
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1309
        return -1;
1310 7434ba6d Philip Gladstone
1311 f7d78f36 Måns Rullgård
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1312 90f9c440 Alex Beregszaszi
1313
    if (ffserver_debug)
1314 77553ae3 Baptiste Coudurier
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1315 115329f1 Diego Biurrun
1316 85f07f22 Fabrice Bellard
    /* find the filename and the optional info string in the request */
1317 bae79c04 Alex Beregszaszi
    p = strchr(url, '?');
1318 85f07f22 Fabrice Bellard
    if (p) {
1319 f7d78f36 Måns Rullgård
        av_strlcpy(info, p, sizeof(info));
1320 85f07f22 Fabrice Bellard
        *p = '\0';
1321 611c5741 Alex Beregszaszi
    } else
1322 85f07f22 Fabrice Bellard
        info[0] = '\0';
1323
1324 f7d78f36 Måns Rullgård
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1325 bae79c04 Alex Beregszaszi
1326 cde25790 Philip Gladstone
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1327
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1328
            useragent = p + 11;
1329
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1330
                useragent++;
1331
            break;
1332
        }
1333
        p = strchr(p, '\n');
1334
        if (!p)
1335
            break;
1336
1337
        p++;
1338
    }
1339
1340 829ac53d Fabrice Bellard
    redir_type = REDIR_NONE;
1341 aa13b573 Stefano Sabatini
    if (av_match_ext(filename, "asx")) {
1342 829ac53d Fabrice Bellard
        redir_type = REDIR_ASX;
1343 7434ba6d Philip Gladstone
        filename[strlen(filename)-1] = 'f';
1344 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "asf") &&
1345 cde25790 Philip Gladstone
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1346
        /* if this isn't WMP or lookalike, return the redirector file */
1347 829ac53d Fabrice Bellard
        redir_type = REDIR_ASF;
1348 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "rpm,ram")) {
1349 829ac53d Fabrice Bellard
        redir_type = REDIR_RAM;
1350 42a63c6a Philip Gladstone
        strcpy(filename + strlen(filename)-2, "m");
1351 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "rtsp")) {
1352 829ac53d Fabrice Bellard
        redir_type = REDIR_RTSP;
1353 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1354 aa13b573 Stefano Sabatini
    } else if (av_match_ext(filename, "sdp")) {
1355 829ac53d Fabrice Bellard
        redir_type = REDIR_SDP;
1356 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1357 42a63c6a Philip Gladstone
    }
1358 115329f1 Diego Biurrun
1359 bae79c04 Alex Beregszaszi
    // "redirect" / request to index.html
1360
    if (!strlen(filename))
1361 f7d78f36 Måns Rullgård
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1362 bae79c04 Alex Beregszaszi
1363 85f07f22 Fabrice Bellard
    stream = first_stream;
1364
    while (stream != NULL) {
1365 8256c0a3 Philip Gladstone
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1366 85f07f22 Fabrice Bellard
            break;
1367
        stream = stream->next;
1368
    }
1369
    if (stream == NULL) {
1370 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1371 77553ae3 Baptiste Coudurier
        http_log("File '%s' not found\n", url);
1372 85f07f22 Fabrice Bellard
        goto send_error;
1373
    }
1374 42a63c6a Philip Gladstone
1375 cde25790 Philip Gladstone
    c->stream = stream;
1376
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1377
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1378
1379
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1380
        c->http_error = 301;
1381
        q = c->buffer;
1382 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1383
                      "HTTP/1.0 301 Moved\r\n"
1384
                      "Location: %s\r\n"
1385
                      "Content-type: text/html\r\n"
1386
                      "\r\n"
1387
                      "<html><head><title>Moved</title></head><body>\r\n"
1388
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1389
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1390 cde25790 Philip Gladstone
        /* prepare output buffer */
1391
        c->buffer_ptr = c->buffer;
1392
        c->buffer_end = q;
1393
        c->state = HTTPSTATE_SEND_HEADER;
1394
        return 0;
1395
    }
1396
1397 3120d2a2 Philip Gladstone
    /* If this is WMP, get the rate information */
1398
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1399 cde25790 Philip Gladstone
        if (modify_current_stream(c, ratebuf)) {
1400 37d3e066 Aurelien Jacobs
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1401 cde25790 Philip Gladstone
                if (c->switch_feed_streams[i] >= 0)
1402
                    do_switch_stream(c, i);
1403
            }
1404
        }
1405 3120d2a2 Philip Gladstone
    }
1406
1407 d8f28a77 Baptiste Coudurier
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1408
        current_bandwidth += stream->bandwidth;
1409
1410 755bfeab Diego Biurrun
    /* If already streaming this feed, do not let start another feeder. */
1411 d0a5513b Alex Beregszaszi
    if (stream->feed_opened) {
1412
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1413 77553ae3 Baptiste Coudurier
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1414 d0a5513b Alex Beregszaszi
        goto send_error;
1415
    }
1416
1417 edfdd798 Alex Beregszaszi
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1418 42a63c6a Philip Gladstone
        c->http_error = 200;
1419
        q = c->buffer;
1420 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1421
                      "HTTP/1.0 200 Server too busy\r\n"
1422
                      "Content-type: text/html\r\n"
1423
                      "\r\n"
1424
                      "<html><head><title>Too busy</title></head><body>\r\n"
1425
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1426 0be4b8d9 Baptiste Coudurier
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1427
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1428 a3aa4fed Baptiste Coudurier
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1429 42a63c6a Philip Gladstone
        /* prepare output buffer */
1430
        c->buffer_ptr = c->buffer;
1431
        c->buffer_end = q;
1432
        c->state = HTTPSTATE_SEND_HEADER;
1433
        return 0;
1434
    }
1435 115329f1 Diego Biurrun
1436 829ac53d Fabrice Bellard
    if (redir_type != REDIR_NONE) {
1437 7434ba6d Philip Gladstone
        char *hostinfo = 0;
1438 115329f1 Diego Biurrun
1439 7434ba6d Philip Gladstone
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1440
            if (strncasecmp(p, "Host:", 5) == 0) {
1441
                hostinfo = p + 5;
1442
                break;
1443
            }
1444
            p = strchr(p, '\n');
1445
            if (!p)
1446
                break;
1447
1448
            p++;
1449
        }
1450
1451
        if (hostinfo) {
1452
            char *eoh;
1453
            char hostbuf[260];
1454
1455
            while (isspace(*hostinfo))
1456
                hostinfo++;
1457
1458
            eoh = strchr(hostinfo, '\n');
1459
            if (eoh) {
1460
                if (eoh[-1] == '\r')
1461
                    eoh--;
1462
1463
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1464
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1465
                    hostbuf[eoh - hostinfo] = 0;
1466
1467
                    c->http_error = 200;
1468
                    q = c->buffer;
1469 829ac53d Fabrice Bellard
                    switch(redir_type) {
1470
                    case REDIR_ASX:
1471 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1472
                                      "HTTP/1.0 200 ASX Follows\r\n"
1473
                                      "Content-type: video/x-ms-asf\r\n"
1474
                                      "\r\n"
1475
                                      "<ASX Version=\"3\">\r\n"
1476
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1477
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1478
                                      "</ASX>\r\n", hostbuf, filename, info);
1479 829ac53d Fabrice Bellard
                        break;
1480
                    case REDIR_RAM:
1481 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1482
                                      "HTTP/1.0 200 RAM Follows\r\n"
1483
                                      "Content-type: audio/x-pn-realaudio\r\n"
1484
                                      "\r\n"
1485
                                      "# Autogenerated by ffserver\r\n"
1486
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1487 829ac53d Fabrice Bellard
                        break;
1488
                    case REDIR_ASF:
1489 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1490
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1491
                                      "Content-type: video/x-ms-asf\r\n"
1492
                                      "\r\n"
1493
                                      "[Reference]\r\n"
1494
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1495 829ac53d Fabrice Bellard
                        break;
1496
                    case REDIR_RTSP:
1497
                        {
1498
                            char hostname[256], *p;
1499
                            /* extract only hostname */
1500 f7d78f36 Måns Rullgård
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1501 829ac53d Fabrice Bellard
                            p = strrchr(hostname, ':');
1502
                            if (p)
1503
                                *p = '\0';
1504 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1505
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1506
                                          /* XXX: incorrect mime type ? */
1507
                                          "Content-type: application/x-rtsp\r\n"
1508
                                          "\r\n"
1509
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1510 829ac53d Fabrice Bellard
                        }
1511
                        break;
1512
                    case REDIR_SDP:
1513
                        {
1514 0c1a9eda Zdenek Kabelac
                            uint8_t *sdp_data;
1515 829ac53d Fabrice Bellard
                            int sdp_data_size, len;
1516
                            struct sockaddr_in my_addr;
1517
1518 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1519
                                          "HTTP/1.0 200 OK\r\n"
1520
                                          "Content-type: application/sdp\r\n"
1521
                                          "\r\n");
1522 829ac53d Fabrice Bellard
1523
                            len = sizeof(my_addr);
1524
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1525 115329f1 Diego Biurrun
1526 829ac53d Fabrice Bellard
                            /* XXX: should use a dynamic buffer */
1527 115329f1 Diego Biurrun
                            sdp_data_size = prepare_sdp_description(stream,
1528
                                                                    &sdp_data,
1529 829ac53d Fabrice Bellard
                                                                    my_addr.sin_addr);
1530
                            if (sdp_data_size > 0) {
1531
                                memcpy(q, sdp_data, sdp_data_size);
1532
                                q += sdp_data_size;
1533
                                *q = '\0';
1534
                                av_free(sdp_data);
1535
                            }
1536
                        }
1537
                        break;
1538
                    default:
1539 0f4e8165 Ronald S. Bultje
                        abort();
1540 829ac53d Fabrice Bellard
                        break;
1541 2effd274 Fabrice Bellard
                    }
1542 7434ba6d Philip Gladstone
1543
                    /* prepare output buffer */
1544
                    c->buffer_ptr = c->buffer;
1545
                    c->buffer_end = q;
1546
                    c->state = HTTPSTATE_SEND_HEADER;
1547
                    return 0;
1548
                }
1549
            }
1550
        }
1551
1552 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1553 7434ba6d Philip Gladstone
        goto send_error;
1554 85f07f22 Fabrice Bellard
    }
1555
1556 a6e14edd Philip Gladstone
    stream->conns_served++;
1557 7434ba6d Philip Gladstone
1558 85f07f22 Fabrice Bellard
    /* XXX: add there authenticate and IP match */
1559
1560 edfdd798 Alex Beregszaszi
    if (c->post) {
1561 85f07f22 Fabrice Bellard
        /* if post, it means a feed is being sent */
1562
        if (!stream->is_feed) {
1563 e16190fa Diego Biurrun
            /* However it might be a status report from WMP! Let us log the
1564
             * data as it might come in handy one day. */
1565 7434ba6d Philip Gladstone
            char *logline = 0;
1566 3120d2a2 Philip Gladstone
            int client_id = 0;
1567 115329f1 Diego Biurrun
1568 7434ba6d Philip Gladstone
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1569
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1570
                    logline = p;
1571
                    break;
1572
                }
1573 611c5741 Alex Beregszaszi
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1574 3120d2a2 Philip Gladstone
                    client_id = strtol(p + 18, 0, 10);
1575 7434ba6d Philip Gladstone
                p = strchr(p, '\n');
1576
                if (!p)
1577
                    break;
1578
1579
                p++;
1580
            }
1581
1582
            if (logline) {
1583
                char *eol = strchr(logline, '\n');
1584
1585
                logline += 17;
1586
1587
                if (eol) {
1588
                    if (eol[-1] == '\r')
1589
                        eol--;
1590 7906085f Falk Hüffner
                    http_log("%.*s\n", (int) (eol - logline), logline);
1591 7434ba6d Philip Gladstone
                    c->suppress_log = 1;
1592
                }
1593
            }
1594 3120d2a2 Philip Gladstone
1595 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1596
            http_log("\nGot request:\n%s\n", c->buffer);
1597 3120d2a2 Philip Gladstone
#endif
1598
1599
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1600
                HTTPContext *wmpc;
1601
1602
                /* Now we have to find the client_id */
1603
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1604
                    if (wmpc->wmp_client_id == client_id)
1605
                        break;
1606
                }
1607
1608 2d563d2f Alex Beregszaszi
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1609
                    wmpc->switch_pending = 1;
1610 3120d2a2 Philip Gladstone
            }
1611 115329f1 Diego Biurrun
1612 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "POST command not handled");
1613 cb275dd9 Philip Gladstone
            c->stream = 0;
1614 85f07f22 Fabrice Bellard
            goto send_error;
1615
        }
1616
        if (http_start_receive_data(c) < 0) {
1617 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "could not open feed");
1618 85f07f22 Fabrice Bellard
            goto send_error;
1619
        }
1620
        c->http_error = 0;
1621
        c->state = HTTPSTATE_RECEIVE_DATA;
1622
        return 0;
1623
    }
1624
1625 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1626 611c5741 Alex Beregszaszi
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1627 cde25790 Philip Gladstone
        http_log("\nGot request:\n%s\n", c->buffer);
1628 3120d2a2 Philip Gladstone
#endif
1629
1630 85f07f22 Fabrice Bellard
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1631 dca21085 Stefano Sabatini
        goto send_status;
1632 85f07f22 Fabrice Bellard
1633
    /* open input stream */
1634
    if (open_input_stream(c, info) < 0) {
1635 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1636 85f07f22 Fabrice Bellard
        goto send_error;
1637
    }
1638
1639
    /* prepare http header */
1640
    q = c->buffer;
1641 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1642 85f07f22 Fabrice Bellard
    mime_type = c->stream->fmt->mime_type;
1643
    if (!mime_type)
1644 087fa475 Alex Beregszaszi
        mime_type = "application/x-octet-stream";
1645 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1646 85f07f22 Fabrice Bellard
1647
    /* for asf, we need extra headers */
1648 8256c0a3 Philip Gladstone
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1649 3120d2a2 Philip Gladstone
        /* Need to allocate a client id */
1650
1651 042819c5 Baptiste Coudurier
        c->wmp_client_id = av_lfg_get(&random_state);
1652 3120d2a2 Philip Gladstone
1653 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);
1654 85f07f22 Fabrice Bellard
    }
1655 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1656
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1657 115329f1 Diego Biurrun
1658 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1659
    c->http_error = 0;
1660
    c->buffer_ptr = c->buffer;
1661
    c->buffer_end = q;
1662
    c->state = HTTPSTATE_SEND_HEADER;
1663
    return 0;
1664
 send_error:
1665
    c->http_error = 404;
1666
    q = c->buffer;
1667 a3aa4fed Baptiste Coudurier
    q += snprintf(q, c->buffer_size,
1668
                  "HTTP/1.0 404 Not Found\r\n"
1669
                  "Content-type: text/html\r\n"
1670
                  "\r\n"
1671 5e567aae Diego Biurrun
                  "<html>\n"
1672
                  "<head><title>404 Not Found</title></head>\n"
1673
                  "<body>%s</body>\n"
1674
                  "</html>\n", msg);
1675 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1676
    c->buffer_ptr = c->buffer;
1677
    c->buffer_end = q;
1678
    c->state = HTTPSTATE_SEND_HEADER;
1679
    return 0;
1680 dca21085 Stefano Sabatini
 send_status:
1681
    compute_status(c);
1682 85f07f22 Fabrice Bellard
    c->http_error = 200; /* horrible : we use this value to avoid
1683
                            going to the send data state */
1684
    c->state = HTTPSTATE_SEND_HEADER;
1685
    return 0;
1686
}
1687
1688 0c1a9eda Zdenek Kabelac
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1689 2ac887ba Philip Gladstone
{
1690
    static const char *suffix = " kMGTP";
1691
    const char *s;
1692
1693 611c5741 Alex Beregszaszi
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1694 2ac887ba Philip Gladstone
1695 4733abcb Måns Rullgård
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1696 2ac887ba Philip Gladstone
}
1697
1698 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c)
1699 85f07f22 Fabrice Bellard
{
1700
    HTTPContext *c1;
1701
    FFStream *stream;
1702 2effd274 Fabrice Bellard
    char *p;
1703 85f07f22 Fabrice Bellard
    time_t ti;
1704 2effd274 Fabrice Bellard
    int i, len;
1705 899681cd Björn Axelsson
    ByteIOContext *pb;
1706 cde25790 Philip Gladstone
1707 899681cd Björn Axelsson
    if (url_open_dyn_buf(&pb) < 0) {
1708 2effd274 Fabrice Bellard
        /* XXX: return an error ? */
1709 cde25790 Philip Gladstone
        c->buffer_ptr = c->buffer;
1710 2effd274 Fabrice Bellard
        c->buffer_end = c->buffer;
1711
        return;
1712 cde25790 Philip Gladstone
    }
1713 85f07f22 Fabrice Bellard
1714 2effd274 Fabrice Bellard
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1715
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1716
    url_fprintf(pb, "Pragma: no-cache\r\n");
1717
    url_fprintf(pb, "\r\n");
1718 115329f1 Diego Biurrun
1719 5e567aae Diego Biurrun
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1720 0679719d Erik Hovland
    if (c->stream->feed_filename[0])
1721 2effd274 Fabrice Bellard
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1722 5e567aae Diego Biurrun
    url_fprintf(pb, "</head>\n<body>");
1723
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1724 85f07f22 Fabrice Bellard
    /* format status */
1725 5e567aae Diego Biurrun
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1726
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1727
    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");
1728 85f07f22 Fabrice Bellard
    stream = first_stream;
1729
    while (stream != NULL) {
1730 42a63c6a Philip Gladstone
        char sfilename[1024];
1731
        char *eosf;
1732
1733 a6e14edd Philip Gladstone
        if (stream->feed != stream) {
1734 f7d78f36 Måns Rullgård
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1735 a6e14edd Philip Gladstone
            eosf = sfilename + strlen(sfilename);
1736
            if (eosf - sfilename >= 4) {
1737 611c5741 Alex Beregszaszi
                if (strcmp(eosf - 4, ".asf") == 0)
1738 a6e14edd Philip Gladstone
                    strcpy(eosf - 4, ".asx");
1739 611c5741 Alex Beregszaszi
                else if (strcmp(eosf - 3, ".rm") == 0)
1740 a6e14edd Philip Gladstone
                    strcpy(eosf - 3, ".ram");
1741 25e3e53d Luca Abeni
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1742 829ac53d Fabrice Bellard
                    /* generate a sample RTSP director if
1743
                       unicast. Generate an SDP redirector if
1744
                       multicast */
1745 2effd274 Fabrice Bellard
                    eosf = strrchr(sfilename, '.');
1746
                    if (!eosf)
1747
                        eosf = sfilename + strlen(sfilename);
1748 829ac53d Fabrice Bellard
                    if (stream->is_multicast)
1749
                        strcpy(eosf, ".sdp");
1750
                    else
1751
                        strcpy(eosf, ".rtsp");
1752 a6e14edd Philip Gladstone
                }
1753 42a63c6a Philip Gladstone
            }
1754 115329f1 Diego Biurrun
1755 5e567aae Diego Biurrun
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1756 a6e14edd Philip Gladstone
                         sfilename, stream->filename);
1757 2effd274 Fabrice Bellard
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1758 2ac887ba Philip Gladstone
                        stream->conns_served);
1759 2effd274 Fabrice Bellard
            fmt_bytecount(pb, stream->bytes_served);
1760 a6e14edd Philip Gladstone
            switch(stream->stream_type) {
1761 ace21da3 Baptiste Coudurier
            case STREAM_TYPE_LIVE: {
1762 a6e14edd Philip Gladstone
                    int audio_bit_rate = 0;
1763
                    int video_bit_rate = 0;
1764 58445440 Zdenek Kabelac
                    const char *audio_codec_name = "";
1765
                    const char *video_codec_name = "";
1766
                    const char *audio_codec_name_extra = "";
1767
                    const char *video_codec_name_extra = "";
1768 a6e14edd Philip Gladstone
1769
                    for(i=0;i<stream->nb_streams;i++) {
1770
                        AVStream *st = stream->streams[i];
1771 01f4895c Michael Niedermayer
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1772
                        switch(st->codec->codec_type) {
1773 a6e14edd Philip Gladstone
                        case CODEC_TYPE_AUDIO:
1774 01f4895c Michael Niedermayer
                            audio_bit_rate += st->codec->bit_rate;
1775 a6e14edd Philip Gladstone
                            if (codec) {
1776
                                if (*audio_codec_name)
1777
                                    audio_codec_name_extra = "...";
1778
                                audio_codec_name = codec->name;
1779
                            }
1780
                            break;
1781
                        case CODEC_TYPE_VIDEO:
1782 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1783 a6e14edd Philip Gladstone
                            if (codec) {
1784
                                if (*video_codec_name)
1785
                                    video_codec_name_extra = "...";
1786
                                video_codec_name = codec->name;
1787
                            }
1788
                            break;
1789 e240a0bb Fabrice Bellard
                        case CODEC_TYPE_DATA:
1790 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1791 e240a0bb Fabrice Bellard
                            break;
1792 a6e14edd Philip Gladstone
                        default:
1793 0f4e8165 Ronald S. Bultje
                            abort();
1794 79c4ea3c Philip Gladstone
                        }
1795 85f07f22 Fabrice Bellard
                    }
1796 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",
1797 a6e14edd Philip Gladstone
                                 stream->fmt->name,
1798 6edd6884 Fabrice Bellard
                                 stream->bandwidth,
1799 a6e14edd Philip Gladstone
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1800
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1801 611c5741 Alex Beregszaszi
                    if (stream->feed)
1802 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1803 611c5741 Alex Beregszaszi
                    else
1804 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1805 2effd274 Fabrice Bellard
                    url_fprintf(pb, "\n");
1806 85f07f22 Fabrice Bellard
                }
1807 a6e14edd Philip Gladstone
                break;
1808
            default:
1809 5e567aae Diego Biurrun
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1810 a6e14edd Philip Gladstone
                break;
1811 85f07f22 Fabrice Bellard
            }
1812
        }
1813
        stream = stream->next;
1814
    }
1815 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
1816 a6e14edd Philip Gladstone
1817
    stream = first_stream;
1818
    while (stream != NULL) {
1819
        if (stream->feed == stream) {
1820 2effd274 Fabrice Bellard
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1821 cde25790 Philip Gladstone
            if (stream->pid) {
1822 2effd274 Fabrice Bellard
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1823 cde25790 Philip Gladstone
1824 2effd274 Fabrice Bellard
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1825
                {
1826
                    FILE *pid_stat;
1827
                    char ps_cmd[64];
1828
1829
                    /* This is somewhat linux specific I guess */
1830 115329f1 Diego Biurrun
                    snprintf(ps_cmd, sizeof(ps_cmd),
1831
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1832 2effd274 Fabrice Bellard
                             stream->pid);
1833 115329f1 Diego Biurrun
1834 2effd274 Fabrice Bellard
                    pid_stat = popen(ps_cmd, "r");
1835
                    if (pid_stat) {
1836
                        char cpuperc[10];
1837
                        char cpuused[64];
1838 115329f1 Diego Biurrun
1839
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1840 2effd274 Fabrice Bellard
                                   cpuused) == 2) {
1841
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1842
                                         cpuperc, cpuused);
1843
                        }
1844
                        fclose(pid_stat);
1845 cde25790 Philip Gladstone
                    }
1846
                }
1847
#endif
1848
1849 2effd274 Fabrice Bellard
                url_fprintf(pb, "<p>");
1850 cde25790 Philip Gladstone
            }
1851 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");
1852 a6e14edd Philip Gladstone
1853
            for (i = 0; i < stream->nb_streams; i++) {
1854
                AVStream *st = stream->streams[i];
1855 01f4895c Michael Niedermayer
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1856 b29f97d1 Zdenek Kabelac
                const char *type = "unknown";
1857 b582f314 Philip Gladstone
                char parameters[64];
1858
1859
                parameters[0] = 0;
1860 a6e14edd Philip Gladstone
1861 01f4895c Michael Niedermayer
                switch(st->codec->codec_type) {
1862 a6e14edd Philip Gladstone
                case CODEC_TYPE_AUDIO:
1863
                    type = "audio";
1864 acdc8520 Alex Beregszaszi
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1865 a6e14edd Philip Gladstone
                    break;
1866
                case CODEC_TYPE_VIDEO:
1867
                    type = "video";
1868 01f4895c Michael Niedermayer
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1869
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1870 a6e14edd Philip Gladstone
                    break;
1871
                default:
1872 0f4e8165 Ronald S. Bultje
                    abort();
1873 a6e14edd Philip Gladstone
                }
1874 2effd274 Fabrice Bellard
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1875 01f4895c Michael Niedermayer
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1876 a6e14edd Philip Gladstone
            }
1877 2effd274 Fabrice Bellard
            url_fprintf(pb, "</table>\n");
1878 a6e14edd Philip Gladstone
1879 115329f1 Diego Biurrun
        }
1880 a6e14edd Philip Gladstone
        stream = stream->next;
1881
    }
1882 115329f1 Diego Biurrun
1883 85f07f22 Fabrice Bellard
    /* connection status */
1884 5e567aae Diego Biurrun
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1885 85f07f22 Fabrice Bellard
1886 5e567aae Diego Biurrun
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1887 85f07f22 Fabrice Bellard
                 nb_connections, nb_max_connections);
1888
1889 5e567aae Diego Biurrun
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1890 6edd6884 Fabrice Bellard
                 current_bandwidth, max_bandwidth);
1891 42a63c6a Philip Gladstone
1892 5e567aae Diego Biurrun
    url_fprintf(pb, "<table>\n");
1893
    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");
1894 85f07f22 Fabrice Bellard
    c1 = first_http_ctx;
1895
    i = 0;
1896 2effd274 Fabrice Bellard
    while (c1 != NULL) {
1897 cde25790 Philip Gladstone
        int bitrate;
1898
        int j;
1899
1900
        bitrate = 0;
1901 2effd274 Fabrice Bellard
        if (c1->stream) {
1902
            for (j = 0; j < c1->stream->nb_streams; j++) {
1903 2d563d2f Alex Beregszaszi
                if (!c1->stream->feed)
1904 01f4895c Michael Niedermayer
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1905 2d563d2f Alex Beregszaszi
                else if (c1->feed_streams[j] >= 0)
1906
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1907 cde25790 Philip Gladstone
            }
1908
        }
1909
1910 85f07f22 Fabrice Bellard
        i++;
1911
        p = inet_ntoa(c1->from_addr.sin_addr);
1912 5e567aae Diego Biurrun
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1913 115329f1 Diego Biurrun
                    i,
1914
                    c1->stream ? c1->stream->filename : "",
1915 2effd274 Fabrice Bellard
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1916 115329f1 Diego Biurrun
                    p,
1917 2effd274 Fabrice Bellard
                    c1->protocol,
1918
                    http_state[c1->state]);
1919
        fmt_bytecount(pb, bitrate);
1920
        url_fprintf(pb, "<td align=right>");
1921
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1922
        url_fprintf(pb, "<td align=right>");
1923
        fmt_bytecount(pb, c1->data_count);
1924
        url_fprintf(pb, "\n");
1925 85f07f22 Fabrice Bellard
        c1 = c1->next;
1926
    }
1927 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
1928 115329f1 Diego Biurrun
1929 85f07f22 Fabrice Bellard
    /* date */
1930
    ti = time(NULL);
1931
    p = ctime(&ti);
1932 5e567aae Diego Biurrun
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1933
    url_fprintf(pb, "</body>\n</html>\n");
1934 85f07f22 Fabrice Bellard
1935 2effd274 Fabrice Bellard
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1936
    c->buffer_ptr = c->pb_buffer;
1937
    c->buffer_end = c->pb_buffer + len;
1938 85f07f22 Fabrice Bellard
}
1939
1940 2effd274 Fabrice Bellard
/* check if the parser needs to be opened for stream i */
1941
static void open_parser(AVFormatContext *s, int i)
1942 85f07f22 Fabrice Bellard
{
1943 2effd274 Fabrice Bellard
    AVStream *st = s->streams[i];
1944
    AVCodec *codec;
1945 31def229 Philip Gladstone
1946 01f4895c Michael Niedermayer
    if (!st->codec->codec) {
1947
        codec = avcodec_find_decoder(st->codec->codec_id);
1948 2effd274 Fabrice Bellard
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1949 01f4895c Michael Niedermayer
            st->codec->parse_only = 1;
1950 611c5741 Alex Beregszaszi
            if (avcodec_open(st->codec, codec) < 0)
1951 01f4895c Michael Niedermayer
                st->codec->parse_only = 0;
1952 cde25790 Philip Gladstone
        }
1953
    }
1954 85f07f22 Fabrice Bellard
}
1955
1956
static int open_input_stream(HTTPContext *c, const char *info)
1957
{
1958
    char buf[128];
1959
    char input_filename[1024];
1960
    AVFormatContext *s;
1961 c351cc7f Baptiste Coudurier
    int buf_size, i, ret;
1962 0c1a9eda Zdenek Kabelac
    int64_t stream_pos;
1963 85f07f22 Fabrice Bellard
1964
    /* find file name */
1965
    if (c->stream->feed) {
1966
        strcpy(input_filename, c->stream->feed->feed_filename);
1967
        buf_size = FFM_PACKET_SIZE;
1968
        /* compute position (absolute time) */
1969 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1970 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 0);
1971 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1972
                return -1;
1973 ace21da3 Baptiste Coudurier
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1974 f747e6d3 Philip Gladstone
            int prebuffer = strtol(buf, 0, 10);
1975 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1976 611c5741 Alex Beregszaszi
        } else
1977 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1978 85f07f22 Fabrice Bellard
    } else {
1979
        strcpy(input_filename, c->stream->feed_filename);
1980
        buf_size = 0;
1981
        /* compute position (relative time) */
1982 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1983 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 1);
1984 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1985
                return -1;
1986 ace21da3 Baptiste Coudurier
        } else
1987 85f07f22 Fabrice Bellard
            stream_pos = 0;
1988
    }
1989
    if (input_filename[0] == '\0')
1990
        return -1;
1991
1992
    /* open stream */
1993 c351cc7f Baptiste Coudurier
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1994
                                  buf_size, c->stream->ap_in)) < 0) {
1995
        http_log("could not open %s: %d\n", input_filename, ret);
1996 85f07f22 Fabrice Bellard
        return -1;
1997 2effd274 Fabrice Bellard
    }
1998 9dc0bc3d Luca Abeni
    s->flags |= AVFMT_FLAG_GENPTS;
1999 85f07f22 Fabrice Bellard
    c->fmt_in = s;
2000 85fe4ae0 Baptiste Coudurier
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2001 20f93c3c Baptiste Coudurier
        http_log("Could not find stream info '%s'\n", input_filename);
2002
        av_close_input_file(s);
2003
        return -1;
2004
    }
2005 115329f1 Diego Biurrun
2006 2effd274 Fabrice Bellard
    /* open each parser */
2007
    for(i=0;i<s->nb_streams;i++)
2008
        open_parser(s, i);
2009
2010
    /* choose stream as clock source (we favorize video stream if
2011
       present) for packet sending */
2012
    c->pts_stream_index = 0;
2013
    for(i=0;i<c->stream->nb_streams;i++) {
2014 115329f1 Diego Biurrun
        if (c->pts_stream_index == 0 &&
2015 01f4895c Michael Niedermayer
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2016 2effd274 Fabrice Bellard
            c->pts_stream_index = i;
2017
        }
2018
    }
2019 85f07f22 Fabrice Bellard
2020 e8d27bc3 Philip Gladstone
#if 1
2021 611c5741 Alex Beregszaszi
    if (c->fmt_in->iformat->read_seek)
2022 60a04f7f Baptiste Coudurier
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2023 e240a0bb Fabrice Bellard
#endif
2024 2effd274 Fabrice Bellard
    /* set the start time (needed for maxtime and RTP packet timing) */
2025
    c->start_time = cur_time;
2026
    c->first_pts = AV_NOPTS_VALUE;
2027 85f07f22 Fabrice Bellard
    return 0;
2028
}
2029
2030 e240a0bb Fabrice Bellard
/* return the server clock (in us) */
2031
static int64_t get_server_clock(HTTPContext *c)
2032 2effd274 Fabrice Bellard
{
2033 e240a0bb Fabrice Bellard
    /* compute current pts value from system time */
2034 c3f58185 Alex Beregszaszi
    return (cur_time - c->start_time) * 1000;
2035 2effd274 Fabrice Bellard
}
2036
2037 e240a0bb Fabrice Bellard
/* return the estimated time at which the current packet must be sent
2038
   (in us) */
2039
static int64_t get_packet_send_clock(HTTPContext *c)
2040 2effd274 Fabrice Bellard
{
2041 e240a0bb Fabrice Bellard
    int bytes_left, bytes_sent, frame_bytes;
2042 115329f1 Diego Biurrun
2043 e240a0bb Fabrice Bellard
    frame_bytes = c->cur_frame_bytes;
2044 611c5741 Alex Beregszaszi
    if (frame_bytes <= 0)
2045 e240a0bb Fabrice Bellard
        return c->cur_pts;
2046 611c5741 Alex Beregszaszi
    else {
2047 e240a0bb Fabrice Bellard
        bytes_left = c->buffer_end - c->buffer_ptr;
2048
        bytes_sent = frame_bytes - bytes_left;
2049
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2050 2effd274 Fabrice Bellard
    }
2051
}
2052
2053
2054
static int http_prepare_data(HTTPContext *c)
2055
{
2056
    int i, len, ret;
2057
    AVFormatContext *ctx;
2058
2059 bc351386 Fabrice Bellard
    av_freep(&c->pb_buffer);
2060 2effd274 Fabrice Bellard
    switch(c->state) {
2061
    case HTTPSTATE_SEND_DATA_HEADER:
2062
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2063 5ee999b8 Aurelien Jacobs
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2064
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2065
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2066
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2067 2effd274 Fabrice Bellard
2068 3d9cc27d Baptiste Coudurier
        for(i=0;i<c->stream->nb_streams;i++) {
2069 2effd274 Fabrice Bellard
            AVStream *st;
2070 bb270c08 Diego Biurrun
            AVStream *src;
2071 2effd274 Fabrice Bellard
            st = av_mallocz(sizeof(AVStream));
2072
            c->fmt_ctx.streams[i] = st;
2073
            /* if file or feed, then just take streams from FFStream struct */
2074 115329f1 Diego Biurrun
            if (!c->stream->feed ||
2075 2effd274 Fabrice Bellard
                c->stream->feed == c->stream)
2076 7c054ea7 Philip Gladstone
                src = c->stream->streams[i];
2077 2effd274 Fabrice Bellard
            else
2078 7c054ea7 Philip Gladstone
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2079
2080 bb270c08 Diego Biurrun
            *st = *src;
2081
            st->priv_data = 0;
2082 01f4895c Michael Niedermayer
            st->codec->frame_number = 0; /* XXX: should be done in
2083 2effd274 Fabrice Bellard
                                           AVStream, not in codec */
2084
        }
2085 3d9cc27d Baptiste Coudurier
        /* set output format parameters */
2086
        c->fmt_ctx.oformat = c->stream->fmt;
2087
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2088
2089 2effd274 Fabrice Bellard
        c->got_key_frame = 0;
2090
2091
        /* prepare header and save header data in a stream */
2092
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2093
            /* XXX: potential leak */
2094
            return -1;
2095
        }
2096 899681cd Björn Axelsson
        c->fmt_ctx.pb->is_streamed = 1;
2097 2effd274 Fabrice Bellard
2098 8aae202e Baptiste Coudurier
        /*
2099
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2100
         * Default value from FFmpeg
2101
         * Try to set it use configuration option
2102
         */
2103
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2104
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2105
2106 3c27199b Fabrice Bellard
        av_set_parameters(&c->fmt_ctx, NULL);
2107 929a9b75 Baptiste Coudurier
        if (av_write_header(&c->fmt_ctx) < 0) {
2108
            http_log("Error writing output header\n");
2109 f75cdda7 Alex Beregszaszi
            return -1;
2110 929a9b75 Baptiste Coudurier
        }
2111 2effd274 Fabrice Bellard
2112 899681cd Björn Axelsson
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2113 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2114
        c->buffer_end = c->pb_buffer + len;
2115
2116
        c->state = HTTPSTATE_SEND_DATA;
2117 85f07f22 Fabrice Bellard
        c->last_packet_sent = 0;
2118
        break;
2119
    case HTTPSTATE_SEND_DATA:
2120
        /* find a new packet */
2121 3b371676 Baptiste Coudurier
        /* read a packet from the input stream */
2122
        if (c->stream->feed)
2123
            ffm_set_write_index(c->fmt_in,
2124
                                c->stream->feed->feed_write_index,
2125
                                c->stream->feed->feed_size);
2126
2127
        if (c->stream->max_time &&
2128
            c->stream->max_time + c->start_time - cur_time < 0)
2129
            /* We have timed out */
2130
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2131
        else {
2132
            AVPacket pkt;
2133
        redo:
2134
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2135
                if (c->stream->feed && c->stream->feed->feed_opened) {
2136
                    /* if coming from feed, it means we reached the end of the
2137
                       ffm file, so must wait for more data */
2138
                    c->state = HTTPSTATE_WAIT_FEED;
2139
                    return 1; /* state changed */
2140 2effd274 Fabrice Bellard
                } else {
2141 3b371676 Baptiste Coudurier
                    if (c->stream->loop) {
2142
                        av_close_input_file(c->fmt_in);
2143
                        c->fmt_in = NULL;
2144
                        if (open_input_stream(c, "") < 0)
2145
                            goto no_loop;
2146
                        goto redo;
2147
                    } else {
2148
                    no_loop:
2149
                        /* must send trailer now because eof or error */
2150
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2151 1bc1cfdd Giancarlo Formicuccia
                    }
2152 3b371676 Baptiste Coudurier
                }
2153
            } else {
2154 084a8912 Baptiste Coudurier
                int source_index = pkt.stream_index;
2155 3b371676 Baptiste Coudurier
                /* update first pts if needed */
2156
                if (c->first_pts == AV_NOPTS_VALUE) {
2157
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2158
                    c->start_time = cur_time;
2159
                }
2160
                /* send it to the appropriate stream */
2161
                if (c->stream->feed) {
2162
                    /* if coming from a feed, select the right stream */
2163
                    if (c->switch_pending) {
2164
                        c->switch_pending = 0;
2165 cde25790 Philip Gladstone
                        for(i=0;i<c->stream->nb_streams;i++) {
2166 3b371676 Baptiste Coudurier
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2167 611c5741 Alex Beregszaszi
                                if (pkt.flags & PKT_FLAG_KEY)
2168 3b371676 Baptiste Coudurier
                                    do_switch_stream(c, i);
2169
                            if (c->switch_feed_streams[i] >= 0)
2170
                                c->switch_pending = 1;
2171 cde25790 Philip Gladstone
                        }
2172 3b371676 Baptiste Coudurier
                    }
2173
                    for(i=0;i<c->stream->nb_streams;i++) {
2174
                        if (c->feed_streams[i] == pkt.stream_index) {
2175 78728064 Baptiste Coudurier
                            AVStream *st = c->fmt_in->streams[source_index];
2176 3b371676 Baptiste Coudurier
                            pkt.stream_index = i;
2177 180b7026 Baptiste Coudurier
                            if (pkt.flags & PKT_FLAG_KEY &&
2178
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2179
                                 c->stream->nb_streams == 1))
2180 0332f549 Baptiste Coudurier
                                c->got_key_frame = 1;
2181
                            if (!c->stream->send_on_key || c->got_key_frame)
2182 3b371676 Baptiste Coudurier
                                goto send_it;
2183
                        }
2184
                    }
2185
                } else {
2186
                    AVCodecContext *codec;
2187 dc3a6a36 Baptiste Coudurier
                    AVStream *ist, *ost;
2188
                send_it:
2189
                    ist = c->fmt_in->streams[source_index];
2190 3b371676 Baptiste Coudurier
                    /* specific handling for RTP: we use several
2191
                       output stream (one for each RTP
2192
                       connection). XXX: need more abstract handling */
2193
                    if (c->is_packetized) {
2194
                        /* compute send time and duration */
2195 8f56ccca Baptiste Coudurier
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2196
                        if (ist->start_time != AV_NOPTS_VALUE)
2197
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2198
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2199 3b371676 Baptiste Coudurier
                        /* find RTP context */
2200
                        c->packet_stream_index = pkt.stream_index;
2201
                        ctx = c->rtp_ctx[c->packet_stream_index];
2202
                        if(!ctx) {
2203 8a0b55ff Baptiste Coudurier
                            av_free_packet(&pkt);
2204 3b371676 Baptiste Coudurier
                            break;
2205 8a0b55ff Baptiste Coudurier
                        }
2206 3b371676 Baptiste Coudurier
                        codec = ctx->streams[0]->codec;
2207
                        /* only one stream per RTP connection */
2208
                        pkt.stream_index = 0;
2209
                    } else {
2210
                        ctx = &c->fmt_ctx;
2211
                        /* Fudge here */
2212 3ab29d8e Baptiste Coudurier
                        codec = ctx->streams[pkt.stream_index]->codec;
2213 3b371676 Baptiste Coudurier
                    }
2214
2215
                    if (c->is_packetized) {
2216
                        int max_packet_size;
2217 90abbdba Ronald S. Bultje
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2218 3b371676 Baptiste Coudurier
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2219
                        else
2220
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2221
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2222
                    } else {
2223
                        ret = url_open_dyn_buf(&ctx->pb);
2224
                    }
2225
                    if (ret < 0) {
2226
                        /* XXX: potential leak */
2227
                        return -1;
2228
                    }
2229 3ab29d8e Baptiste Coudurier
                    ost = ctx->streams[pkt.stream_index];
2230
2231 b0675954 Baptiste Coudurier
                    ctx->pb->is_streamed = 1;
2232 3b371676 Baptiste Coudurier
                    if (pkt.dts != AV_NOPTS_VALUE)
2233 d80904cc Baptiste Coudurier
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2234 3b371676 Baptiste Coudurier
                    if (pkt.pts != AV_NOPTS_VALUE)
2235 d80904cc Baptiste Coudurier
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2236
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2237 3766ed72 Baptiste Coudurier
                    if (av_write_frame(ctx, &pkt) < 0) {
2238
                        http_log("Error writing frame to output\n");
2239 3b371676 Baptiste Coudurier
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2240 3766ed72 Baptiste Coudurier
                    }
2241 3b371676 Baptiste Coudurier
2242
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2243
                    c->cur_frame_bytes = len;
2244
                    c->buffer_ptr = c->pb_buffer;
2245
                    c->buffer_end = c->pb_buffer + len;
2246
2247
                    codec->frame_number++;
2248
                    if (len == 0) {
2249
                        av_free_packet(&pkt);
2250
                        goto redo;
2251 f747e6d3 Philip Gladstone
                    }
2252 85f07f22 Fabrice Bellard
                }
2253 3b371676 Baptiste Coudurier
                av_free_packet(&pkt);
2254 85f07f22 Fabrice Bellard
            }
2255 3b371676 Baptiste Coudurier
        }
2256 85f07f22 Fabrice Bellard
        break;
2257
    default:
2258
    case HTTPSTATE_SEND_DATA_TRAILER:
2259
        /* last packet test ? */
2260 2effd274 Fabrice Bellard
        if (c->last_packet_sent || c->is_packetized)
2261 85f07f22 Fabrice Bellard
            return -1;
2262 2effd274 Fabrice Bellard
        ctx = &c->fmt_ctx;
2263 85f07f22 Fabrice Bellard
        /* prepare header */
2264 2effd274 Fabrice Bellard
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2265
            /* XXX: potential leak */
2266
            return -1;
2267
        }
2268 58bd615f Baptiste Coudurier
        c->fmt_ctx.pb->is_streamed = 1;
2269 2effd274 Fabrice Bellard
        av_write_trailer(ctx);
2270 899681cd Björn Axelsson
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2271 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2272
        c->buffer_end = c->pb_buffer + len;
2273
2274 85f07f22 Fabrice Bellard
        c->last_packet_sent = 1;
2275
        break;
2276
    }
2277
    return 0;
2278
}
2279
2280
/* should convert the format at the same time */
2281 bc351386 Fabrice Bellard
/* send data starting at c->buffer_ptr to the output connection
2282
   (either UDP or TCP connection) */
2283 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c)
2284 85f07f22 Fabrice Bellard
{
2285 e240a0bb Fabrice Bellard
    int len, ret;
2286 85f07f22 Fabrice Bellard
2287 bc351386 Fabrice Bellard
    for(;;) {
2288
        if (c->buffer_ptr >= c->buffer_end) {
2289
            ret = http_prepare_data(c);
2290
            if (ret < 0)
2291
                return -1;
2292 611c5741 Alex Beregszaszi
            else if (ret != 0)
2293 bc351386 Fabrice Bellard
                /* state change requested */
2294
                break;
2295 2effd274 Fabrice Bellard
        } else {
2296 bc351386 Fabrice Bellard
            if (c->is_packetized) {
2297
                /* RTP data output */
2298
                len = c->buffer_end - c->buffer_ptr;
2299
                if (len < 4) {
2300
                    /* fail safe - should never happen */
2301
                fail1:
2302
                    c->buffer_ptr = c->buffer_end;
2303 2effd274 Fabrice Bellard
                    return 0;
2304
                }
2305 bc351386 Fabrice Bellard
                len = (c->buffer_ptr[0] << 24) |
2306
                    (c->buffer_ptr[1] << 16) |
2307
                    (c->buffer_ptr[2] << 8) |
2308
                    (c->buffer_ptr[3]);
2309
                if (len > (c->buffer_end - c->buffer_ptr))
2310
                    goto fail1;
2311 e240a0bb Fabrice Bellard
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2312
                    /* nothing to send yet: we can wait */
2313
                    return 0;
2314
                }
2315
2316
                c->data_count += len;
2317
                update_datarate(&c->datarate, c->data_count);
2318
                if (c->stream)
2319
                    c->stream->bytes_served += len;
2320
2321 90abbdba Ronald S. Bultje
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2322 bc351386 Fabrice Bellard
                    /* RTP packets are sent inside the RTSP TCP connection */
2323 899681cd Björn Axelsson
                    ByteIOContext *pb;
2324 bc351386 Fabrice Bellard
                    int interleaved_index, size;
2325
                    uint8_t header[4];
2326
                    HTTPContext *rtsp_c;
2327 115329f1 Diego Biurrun
2328 bc351386 Fabrice Bellard
                    rtsp_c = c->rtsp_c;
2329
                    /* if no RTSP connection left, error */
2330
                    if (!rtsp_c)
2331
                        return -1;
2332
                    /* if already sending something, then wait. */
2333 611c5741 Alex Beregszaszi
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2334 bc351386 Fabrice Bellard
                        break;
2335 899681cd Björn Axelsson
                    if (url_open_dyn_buf(&pb) < 0)
2336 bc351386 Fabrice Bellard
                        goto fail1;
2337
                    interleaved_index = c->packet_stream_index * 2;
2338
                    /* RTCP packets are sent at odd indexes */
2339
                    if (c->buffer_ptr[1] == 200)
2340
                        interleaved_index++;
2341
                    /* write RTSP TCP header */
2342
                    header[0] = '$';
2343
                    header[1] = interleaved_index;
2344
                    header[2] = len >> 8;
2345
                    header[3] = len;
2346
                    put_buffer(pb, header, 4);
2347
                    /* write RTP packet data */
2348
                    c->buffer_ptr += 4;
2349
                    put_buffer(pb, c->buffer_ptr, len);
2350
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2351
                    /* prepare asynchronous TCP sending */
2352
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2353
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2354 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2355 115329f1 Diego Biurrun
2356 e240a0bb Fabrice Bellard
                    /* send everything we can NOW */
2357 c60202df Alex Beregszaszi
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2358
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2359 611c5741 Alex Beregszaszi
                    if (len > 0)
2360 e240a0bb Fabrice Bellard
                        rtsp_c->packet_buffer_ptr += len;
2361
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2362
                        /* if we could not send all the data, we will
2363
                           send it later, so a new state is needed to
2364
                           "lock" the RTSP TCP connection */
2365
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2366
                        break;
2367 611c5741 Alex Beregszaszi
                    } else
2368 e240a0bb Fabrice Bellard
                        /* all data has been sent */
2369
                        av_freep(&c->packet_buffer);
2370
                } else {
2371
                    /* send RTP packet directly in UDP */
2372 bc351386 Fabrice Bellard
                    c->buffer_ptr += 4;
2373 115329f1 Diego Biurrun
                    url_write(c->rtp_handles[c->packet_stream_index],
2374 bc351386 Fabrice Bellard
                              c->buffer_ptr, len);
2375 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2376
                    /* here we continue as we can send several packets per 10 ms slot */
2377 bc351386 Fabrice Bellard
                }
2378
            } else {
2379
                /* TCP data output */
2380 c60202df Alex Beregszaszi
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2381 bc351386 Fabrice Bellard
                if (len < 0) {
2382 8da4034f Alex Beregszaszi
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2383 611c5741 Alex Beregszaszi
                        ff_neterrno() != FF_NETERROR(EINTR))
2384 bc351386 Fabrice Bellard
                        /* error : close connection */
2385
                        return -1;
2386 611c5741 Alex Beregszaszi
                    else
2387 bc351386 Fabrice Bellard
                        return 0;
2388 611c5741 Alex Beregszaszi
                } else
2389 bc351386 Fabrice Bellard
                    c->buffer_ptr += len;
2390 611c5741 Alex Beregszaszi
2391 e240a0bb Fabrice Bellard
                c->data_count += len;
2392
                update_datarate(&c->datarate, c->data_count);
2393
                if (c->stream)
2394
                    c->stream->bytes_served += len;
2395
                break;
2396 2effd274 Fabrice Bellard
            }
2397 85f07f22 Fabrice Bellard
        }
2398 bc351386 Fabrice Bellard
    } /* for(;;) */
2399 85f07f22 Fabrice Bellard
    return 0;
2400
}
2401
2402
static int http_start_receive_data(HTTPContext *c)
2403
{
2404
    int fd;
2405
2406
    if (c->stream->feed_opened)
2407
        return -1;
2408
2409 e322ea48 Philip Gladstone
    /* Don't permit writing to this one */
2410
    if (c->stream->readonly)
2411
        return -1;
2412
2413 85f07f22 Fabrice Bellard
    /* open feed */
2414
    fd = open(c->stream->feed_filename, O_RDWR);
2415 929a9b75 Baptiste Coudurier
    if (fd < 0) {
2416
        http_log("Error opening feeder file: %s\n", strerror(errno));
2417 85f07f22 Fabrice Bellard
        return -1;
2418 929a9b75 Baptiste Coudurier
    }
2419 85f07f22 Fabrice Bellard
    c->feed_fd = fd;
2420 115329f1 Diego Biurrun
2421 861ec13a Baptiste Coudurier
    if (c->stream->truncate) {
2422
        /* truncate feed file */
2423
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2424
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2425
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2426
    } else {
2427 1f611549 Baptiste Coudurier
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2428
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2429
            return -1;
2430
        }
2431 861ec13a Baptiste Coudurier
    }
2432
2433 7e24aa0c Baptiste Coudurier
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2434 85f07f22 Fabrice Bellard
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2435
    lseek(fd, 0, SEEK_SET);
2436
2437
    /* init buffer input */
2438
    c->buffer_ptr = c->buffer;
2439
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2440
    c->stream->feed_opened = 1;
2441 fd7bec5e Måns Rullgård
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2442 85f07f22 Fabrice Bellard
    return 0;
2443
}
2444 115329f1 Diego Biurrun
2445 85f07f22 Fabrice Bellard
static int http_receive_data(HTTPContext *c)
2446
{
2447
    HTTPContext *c1;
2448 19c8c4ec Ronald S. Bultje
    int len, loop_run = 0;
2449 85f07f22 Fabrice Bellard
2450 19c8c4ec Ronald S. Bultje
    while (c->chunked_encoding && !c->chunk_size &&
2451
           c->buffer_end > c->buffer_ptr) {
2452
        /* read chunk header, if present */
2453
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2454
2455
        if (len < 0) {
2456
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2457
                ff_neterrno() != FF_NETERROR(EINTR))
2458
                /* error : close connection */
2459
                goto fail;
2460
        } else if (len == 0) {
2461
            /* end of connection : close it */
2462
            goto fail;
2463
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2464
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2465
            c->chunk_size = strtol(c->buffer, 0, 16);
2466
            if (c->chunk_size == 0) // end of stream
2467
                goto fail;
2468
            c->buffer_ptr = c->buffer;
2469
            break;
2470
        } else if (++loop_run > 10) {
2471
            /* no chunk header, abort */
2472
            goto fail;
2473
        } else {
2474
            c->buffer_ptr++;
2475
        }
2476
    }
2477 a6e14edd Philip Gladstone
2478 19c8c4ec Ronald S. Bultje
    if (c->buffer_end > c->buffer_ptr) {
2479
        len = recv(c->fd, c->buffer_ptr,
2480
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2481 a6e14edd Philip Gladstone
        if (len < 0) {
2482 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2483 611c5741 Alex Beregszaszi
                ff_neterrno() != FF_NETERROR(EINTR))
2484 a6e14edd Philip Gladstone
                /* error : close connection */
2485
                goto fail;
2486 611c5741 Alex Beregszaszi
        } else if (len == 0)
2487 a6e14edd Philip Gladstone
            /* end of connection : close it */
2488
            goto fail;
2489 611c5741 Alex Beregszaszi
        else {
2490 19c8c4ec Ronald S. Bultje
            c->chunk_size -= len;
2491 a6e14edd Philip Gladstone
            c->buffer_ptr += len;
2492
            c->data_count += len;
2493 5eb765ef Philip Gladstone
            update_datarate(&c->datarate, c->data_count);
2494 a6e14edd Philip Gladstone
        }
2495
    }
2496
2497 d445a7e9 Philip Gladstone
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2498
        if (c->buffer[0] != 'f' ||
2499
            c->buffer[1] != 'm') {
2500
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2501
            goto fail;
2502
        }
2503
    }
2504
2505 85f07f22 Fabrice Bellard
    if (c->buffer_ptr >= c->buffer_end) {
2506 f747e6d3 Philip Gladstone
        FFStream *feed = c->stream;
2507 85f07f22 Fabrice Bellard
        /* a packet has been received : write it in the store, except
2508
           if header */
2509
        if (c->data_count > FFM_PACKET_SIZE) {
2510 115329f1 Diego Biurrun
2511 949b1a13 Steve L'Homme
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2512 85f07f22 Fabrice Bellard
            /* XXX: use llseek or url_seek */
2513
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2514 929a9b75 Baptiste Coudurier
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2515
                http_log("Error writing to feed file: %s\n", strerror(errno));
2516
                goto fail;
2517
            }
2518 115329f1 Diego Biurrun
2519 85f07f22 Fabrice Bellard
            feed->feed_write_index += FFM_PACKET_SIZE;
2520
            /* update file size */
2521
            if (feed->feed_write_index > c->stream->feed_size)
2522
                feed->feed_size = feed->feed_write_index;
2523
2524
            /* handle wrap around if max file size reached */
2525 6b0bdc75 Alex Beregszaszi
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2526 85f07f22 Fabrice Bellard
                feed->feed_write_index = FFM_PACKET_SIZE;
2527
2528
            /* write index */
2529 2779cdad Patrik Kullman
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2530
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2531
                goto fail;
2532
            }
2533 85f07f22 Fabrice Bellard
2534
            /* wake up any waiting connections */
2535
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2536 115329f1 Diego Biurrun
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2537 611c5741 Alex Beregszaszi
                    c1->stream->feed == c->stream->feed)
2538 85f07f22 Fabrice Bellard
                    c1->state = HTTPSTATE_SEND_DATA;
2539
            }
2540 f747e6d3 Philip Gladstone
        } else {
2541
            /* We have a header in our hands that contains useful data */
2542 f2972c8c Baptiste Coudurier
            AVFormatContext *s = NULL;
2543
            ByteIOContext *pb;
2544 bd7cf6ad Fabrice Bellard
            AVInputFormat *fmt_in;
2545 f747e6d3 Philip Gladstone
            int i;
2546
2547 bd7cf6ad Fabrice Bellard
            /* use feed output format name to find corresponding input format */
2548
            fmt_in = av_find_input_format(feed->fmt->name);
2549
            if (!fmt_in)
2550
                goto fail;
2551
2552 697efa36 Baptiste Coudurier
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2553
            pb->is_streamed = 1;
2554
2555 e6f0deab Baptiste Coudurier
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2556
                av_free(pb);
2557
                goto fail;
2558
            }
2559 f747e6d3 Philip Gladstone
2560
            /* Now we have the actual streams */
2561 f2972c8c Baptiste Coudurier
            if (s->nb_streams != feed->nb_streams) {
2562
                av_close_input_stream(s);
2563 86771c68 Baptiste Coudurier
                av_free(pb);
2564 77553ae3 Baptiste Coudurier
                http_log("Feed '%s' stream number does not match registered feed\n",
2565
                         c->stream->feed_filename);
2566 f747e6d3 Philip Gladstone
                goto fail;
2567
            }
2568 f2972c8c Baptiste Coudurier
2569 cb51aef1 Baptiste Coudurier
            for (i = 0; i < s->nb_streams; i++) {
2570
                AVStream *fst = feed->streams[i];
2571
                AVStream *st = s->streams[i];
2572
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2573
                if (fst->codec->extradata_size) {
2574
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2575
                    if (!fst->codec->extradata)
2576
                        goto fail;
2577
                    memcpy(fst->codec->extradata, st->codec->extradata,
2578
                           fst->codec->extradata_size);
2579
                }
2580
            }
2581 f2972c8c Baptiste Coudurier
2582
            av_close_input_stream(s);
2583 86771c68 Baptiste Coudurier
            av_free(pb);
2584 85f07f22 Fabrice Bellard
        }
2585
        c->buffer_ptr = c->buffer;
2586
    }
2587
2588
    return 0;
2589
 fail:
2590
    c->stream->feed_opened = 0;
2591
    close(c->feed_fd);
2592 c1593d0e Baptiste Coudurier
    /* wake up any waiting connections to stop waiting for feed */
2593
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2594
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2595
            c1->stream->feed == c->stream->feed)
2596
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2597
    }
2598 85f07f22 Fabrice Bellard
    return -1;
2599
}
2600
2601 2effd274 Fabrice Bellard
/********************************************************************/
2602
/* RTSP handling */
2603
2604
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2605
{
2606
    const char *str;
2607
    time_t ti;
2608
    char *p;
2609
    char buf2[32];
2610
2611
    switch(error_number) {
2612 7e665cd3 Luca Abeni
    case RTSP_STATUS_OK:
2613
        str = "OK";
2614
        break;
2615
    case RTSP_STATUS_METHOD:
2616
        str = "Method Not Allowed";
2617
        break;
2618
    case RTSP_STATUS_BANDWIDTH:
2619
        str = "Not Enough Bandwidth";
2620
        break;
2621
    case RTSP_STATUS_SESSION:
2622
        str = "Session Not Found";
2623
        break;
2624
    case RTSP_STATUS_STATE:
2625
        str = "Method Not Valid in This State";
2626
        break;
2627
    case RTSP_STATUS_AGGREGATE:
2628
        str = "Aggregate operation not allowed";
2629
        break;
2630
    case RTSP_STATUS_ONLY_AGGREGATE:
2631
        str = "Only aggregate operation allowed";
2632
        break;
2633
    case RTSP_STATUS_TRANSPORT:
2634
        str = "Unsupported transport";
2635
        break;
2636
    case RTSP_STATUS_INTERNAL:
2637
        str = "Internal Server Error";
2638
        break;
2639
    case RTSP_STATUS_SERVICE:
2640
        str = "Service Unavailable";
2641
        break;
2642
    case RTSP_STATUS_VERSION:
2643
        str = "RTSP Version not supported";
2644
        break;
2645 2effd274 Fabrice Bellard
    default:
2646
        str = "Unknown Error";
2647
        break;
2648
    }
2649 115329f1 Diego Biurrun
2650 2effd274 Fabrice Bellard
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2651
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2652
2653
    /* output GMT time */
2654
    ti = time(NULL);
2655
    p = ctime(&ti);
2656
    strcpy(buf2, p);
2657
    p = buf2 + strlen(p) - 1;
2658
    if (*p == '\n')
2659
        *p = '\0';
2660
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2661
}
2662
2663
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)