Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 99ed41a8

History | View | Annotate | Download (150 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
#include "libavformat/rtp.h"
36
#include "libavformat/rtsp.h"
37 959da985 Stefano Sabatini
#include "libavutil/avstring.h"
38
#include "libavutil/random.h"
39 2bb6eba2 Aurelien Jacobs
#include "libavutil/intreadwrite.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 4568325a Roman Shaposhnik
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
51 85f07f22 Fabrice Bellard
#include <time.h>
52 5eb765ef Philip Gladstone
#include <sys/wait.h>
53 85f07f22 Fabrice Bellard
#include <signal.h>
54 b250f9c6 Aurelien Jacobs
#if HAVE_DLFCN_H
55 2effd274 Fabrice Bellard
#include <dlfcn.h>
56 6638d424 Philip Gladstone
#endif
57 2effd274 Fabrice Bellard
58 4ce5df08 Stefano Sabatini
#include "cmdutils.h"
59 85f07f22 Fabrice Bellard
60 c367d067 Michael Niedermayer
#undef exit
61
62 64555bd9 Michael Niedermayer
const char program_name[] = "FFserver";
63 ea9c581f Stefano Sabatini
const int program_birth_year = 2000;
64 86074ed1 Stefano Sabatini
65 5a635bc7 Stefano Sabatini
static const OptionDef options[];
66
67 85f07f22 Fabrice Bellard
enum HTTPState {
68
    HTTPSTATE_WAIT_REQUEST,
69
    HTTPSTATE_SEND_HEADER,
70
    HTTPSTATE_SEND_DATA_HEADER,
71 2effd274 Fabrice Bellard
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
72 85f07f22 Fabrice Bellard
    HTTPSTATE_SEND_DATA_TRAILER,
73 115329f1 Diego Biurrun
    HTTPSTATE_RECEIVE_DATA,
74 2effd274 Fabrice Bellard
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
75
    HTTPSTATE_READY,
76
77
    RTSPSTATE_WAIT_REQUEST,
78
    RTSPSTATE_SEND_REPLY,
79 bc351386 Fabrice Bellard
    RTSPSTATE_SEND_PACKET,
80 85f07f22 Fabrice Bellard
};
81
82 9507a12e Baptiste Coudurier
static const char *http_state[] = {
83 2effd274 Fabrice Bellard
    "HTTP_WAIT_REQUEST",
84
    "HTTP_SEND_HEADER",
85
86 85f07f22 Fabrice Bellard
    "SEND_DATA_HEADER",
87
    "SEND_DATA",
88
    "SEND_DATA_TRAILER",
89
    "RECEIVE_DATA",
90
    "WAIT_FEED",
91 2effd274 Fabrice Bellard
    "READY",
92
93
    "RTSP_WAIT_REQUEST",
94
    "RTSP_SEND_REPLY",
95 bc351386 Fabrice Bellard
    "RTSP_SEND_PACKET",
96 85f07f22 Fabrice Bellard
};
97
98 cde25790 Philip Gladstone
#define IOBUFFER_INIT_SIZE 8192
99 85f07f22 Fabrice Bellard
100
/* timeouts are in ms */
101 2effd274 Fabrice Bellard
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
102
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
103
104 85f07f22 Fabrice Bellard
#define SYNC_TIMEOUT (10 * 1000)
105
106 5eb765ef Philip Gladstone
typedef struct {
107 0c1a9eda Zdenek Kabelac
    int64_t count1, count2;
108 c3f58185 Alex Beregszaszi
    int64_t time1, time2;
109 5eb765ef Philip Gladstone
} DataRateData;
110
111 85f07f22 Fabrice Bellard
/* context associated with one connection */
112
typedef struct HTTPContext {
113
    enum HTTPState state;
114
    int fd; /* socket file descriptor */
115
    struct sockaddr_in from_addr; /* origin */
116
    struct pollfd *poll_entry; /* used when polling */
117 c3f58185 Alex Beregszaszi
    int64_t timeout;
118 0c1a9eda Zdenek Kabelac
    uint8_t *buffer_ptr, *buffer_end;
119 85f07f22 Fabrice Bellard
    int http_error;
120 edfdd798 Alex Beregszaszi
    int post;
121 85f07f22 Fabrice Bellard
    struct HTTPContext *next;
122 42a63c6a Philip Gladstone
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
123 0c1a9eda Zdenek Kabelac
    int64_t data_count;
124 85f07f22 Fabrice Bellard
    /* feed input */
125
    int feed_fd;
126
    /* input format handling */
127
    AVFormatContext *fmt_in;
128 c3f58185 Alex Beregszaszi
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
129 0c1a9eda Zdenek Kabelac
    int64_t first_pts;            /* initial pts value */
130 e240a0bb Fabrice Bellard
    int64_t cur_pts;             /* current pts value from the stream in us */
131
    int64_t cur_frame_duration;  /* duration of the current frame in us */
132
    int cur_frame_bytes;       /* output frame size, needed to compute
133
                                  the time at which we send each
134
                                  packet */
135
    int pts_stream_index;        /* stream we choose as clock reference */
136
    int64_t cur_clock;           /* current clock reference value in us */
137 85f07f22 Fabrice Bellard
    /* output format handling */
138
    struct FFStream *stream;
139 cde25790 Philip Gladstone
    /* -1 is invalid stream */
140
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
141
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
142
    int switch_pending;
143 2effd274 Fabrice Bellard
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
144 85f07f22 Fabrice Bellard
    int last_packet_sent; /* true if last data packet was sent */
145 7434ba6d Philip Gladstone
    int suppress_log;
146 5eb765ef Philip Gladstone
    DataRateData datarate;
147 3120d2a2 Philip Gladstone
    int wmp_client_id;
148 7434ba6d Philip Gladstone
    char protocol[16];
149
    char method[16];
150
    char url[128];
151 cde25790 Philip Gladstone
    int buffer_size;
152 0c1a9eda Zdenek Kabelac
    uint8_t *buffer;
153 2effd274 Fabrice Bellard
    int is_packetized; /* if true, the stream is packetized */
154
    int packet_stream_index; /* current stream for output in state machine */
155 115329f1 Diego Biurrun
156 2effd274 Fabrice Bellard
    /* RTSP state specific */
157 0c1a9eda Zdenek Kabelac
    uint8_t *pb_buffer; /* XXX: use that in all the code */
158 2effd274 Fabrice Bellard
    ByteIOContext *pb;
159
    int seq; /* RTSP sequence number */
160 115329f1 Diego Biurrun
161 2effd274 Fabrice Bellard
    /* RTP state specific */
162 90abbdba Ronald S. Bultje
    enum RTSPLowerTransport rtp_protocol;
163 2effd274 Fabrice Bellard
    char session_id[32]; /* session id */
164
    AVFormatContext *rtp_ctx[MAX_STREAMS];
165 e240a0bb Fabrice Bellard
166 bc351386 Fabrice Bellard
    /* RTP/UDP specific */
167
    URLContext *rtp_handles[MAX_STREAMS];
168
169
    /* RTP/TCP specific */
170
    struct HTTPContext *rtsp_c;
171
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
172 85f07f22 Fabrice Bellard
} HTTPContext;
173
174
/* each generated stream is described here */
175
enum StreamType {
176
    STREAM_TYPE_LIVE,
177
    STREAM_TYPE_STATUS,
178 cde25790 Philip Gladstone
    STREAM_TYPE_REDIRECT,
179 85f07f22 Fabrice Bellard
};
180
181 8256c0a3 Philip Gladstone
enum IPAddressAction {
182
    IP_ALLOW = 1,
183
    IP_DENY,
184
};
185
186
typedef struct IPAddressACL {
187
    struct IPAddressACL *next;
188
    enum IPAddressAction action;
189 efa04ce2 Philip Gladstone
    /* These are in host order */
190 8256c0a3 Philip Gladstone
    struct in_addr first;
191
    struct in_addr last;
192
} IPAddressACL;
193
194 85f07f22 Fabrice Bellard
/* description of each stream of the ffserver.conf file */
195
typedef struct FFStream {
196
    enum StreamType stream_type;
197
    char filename[1024];     /* stream filename */
198 2effd274 Fabrice Bellard
    struct FFStream *feed;   /* feed we are using (can be null if
199
                                coming from file) */
200 e240a0bb Fabrice Bellard
    AVFormatParameters *ap_in; /* input parameters */
201
    AVInputFormat *ifmt;       /* if non NULL, force input format */
202 bd7cf6ad Fabrice Bellard
    AVOutputFormat *fmt;
203 8256c0a3 Philip Gladstone
    IPAddressACL *acl;
204 85f07f22 Fabrice Bellard
    int nb_streams;
205 42a63c6a Philip Gladstone
    int prebuffer;      /* Number of millseconds early to start */
206 c3f58185 Alex Beregszaszi
    int64_t max_time;      /* Number of milliseconds to run */
207 79c4ea3c Philip Gladstone
    int send_on_key;
208 85f07f22 Fabrice Bellard
    AVStream *streams[MAX_STREAMS];
209
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
210
    char feed_filename[1024]; /* file name of the feed storage, or
211
                                 input file name for a stream */
212 2ac887ba Philip Gladstone
    char author[512];
213
    char title[512];
214
    char copyright[512];
215
    char comment[512];
216 cde25790 Philip Gladstone
    pid_t pid;  /* Of ffmpeg process */
217 5eb765ef Philip Gladstone
    time_t pid_start;  /* Of ffmpeg process */
218 cde25790 Philip Gladstone
    char **child_argv;
219 85f07f22 Fabrice Bellard
    struct FFStream *next;
220 177d2564 Baptiste Coudurier
    unsigned bandwidth; /* bandwidth, in kbits/s */
221 2effd274 Fabrice Bellard
    /* RTSP options */
222
    char *rtsp_option;
223 829ac53d Fabrice Bellard
    /* multicast specific */
224
    int is_multicast;
225
    struct in_addr multicast_ip;
226
    int multicast_port; /* first port used for multicast */
227 6edd6884 Fabrice Bellard
    int multicast_ttl;
228
    int loop; /* if true, send the stream in loops (only meaningful if file) */
229 829ac53d Fabrice Bellard
230 85f07f22 Fabrice Bellard
    /* feed specific */
231 2effd274 Fabrice Bellard
    int feed_opened;     /* true if someone is writing to the feed */
232 85f07f22 Fabrice Bellard
    int is_feed;         /* true if it is a feed */
233 e322ea48 Philip Gladstone
    int readonly;        /* True if writing is prohibited to the file */
234 a6e14edd Philip Gladstone
    int conns_served;
235 0c1a9eda Zdenek Kabelac
    int64_t bytes_served;
236 6b0bdc75 Alex Beregszaszi
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
237 8bfb108b Diego Biurrun
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
238 0c1a9eda Zdenek Kabelac
    int64_t feed_size;          /* current size of feed */
239 85f07f22 Fabrice Bellard
    struct FFStream *next_feed;
240
} FFStream;
241
242
typedef struct FeedData {
243
    long long data_count;
244 8bfb108b Diego Biurrun
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
245 85f07f22 Fabrice Bellard
} FeedData;
246
247 18405874 Alex Beregszaszi
static struct sockaddr_in my_http_addr;
248
static struct sockaddr_in my_rtsp_addr;
249 2effd274 Fabrice Bellard
250 33f5e2ec Alex Beregszaszi
static char logfilename[1024];
251
static HTTPContext *first_http_ctx;
252
static FFStream *first_feed;   /* contains only feeds */
253
static FFStream *first_stream; /* contains all streams, including feeds */
254 85f07f22 Fabrice Bellard
255 2effd274 Fabrice Bellard
static void new_connection(int server_fd, int is_rtsp);
256
static void close_connection(HTTPContext *c);
257
258
/* HTTP handling */
259
static int handle_connection(HTTPContext *c);
260 85f07f22 Fabrice Bellard
static int http_parse_request(HTTPContext *c);
261 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c);
262 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c);
263 85f07f22 Fabrice Bellard
static int open_input_stream(HTTPContext *c, const char *info);
264
static int http_start_receive_data(HTTPContext *c);
265
static int http_receive_data(HTTPContext *c);
266 2effd274 Fabrice Bellard
267
/* RTSP handling */
268
static int rtsp_parse_request(HTTPContext *c);
269
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
270 0df65975 Andriy Rysin
static void rtsp_cmd_options(HTTPContext *c, const char *url);
271 2effd274 Fabrice Bellard
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
272
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
273
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
274
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
275
276 829ac53d Fabrice Bellard
/* SDP handling */
277 115329f1 Diego Biurrun
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
278 829ac53d Fabrice Bellard
                                   struct in_addr my_ip);
279
280 2effd274 Fabrice Bellard
/* RTP handling */
281 115329f1 Diego Biurrun
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
282 bc351386 Fabrice Bellard
                                       FFStream *stream, const char *session_id,
283 90abbdba Ronald S. Bultje
                                       enum RTSPLowerTransport rtp_protocol);
284 115329f1 Diego Biurrun
static int rtp_new_av_stream(HTTPContext *c,
285 bc351386 Fabrice Bellard
                             int stream_index, struct sockaddr_in *dest_addr,
286
                             HTTPContext *rtsp_c);
287 85f07f22 Fabrice Bellard
288 cde25790 Philip Gladstone
static const char *my_program_name;
289 d6562d2c Philip Gladstone
static const char *my_program_dir;
290 cde25790 Philip Gladstone
291 5a635bc7 Stefano Sabatini
static const char *config_filename;
292 2ac887ba Philip Gladstone
static int ffserver_debug;
293 2effd274 Fabrice Bellard
static int ffserver_daemon;
294 2ac887ba Philip Gladstone
static int no_launch;
295 5eb765ef Philip Gladstone
static int need_to_start_children;
296 2ac887ba Philip Gladstone
297 1c9ff179 Stefano Sabatini
/* maximum number of simultaneous HTTP connections */
298
static unsigned int nb_max_http_connections = 2000;
299 4af92de6 Stefano Sabatini
static unsigned int nb_max_connections = 5;
300
static unsigned int nb_connections;
301 85f07f22 Fabrice Bellard
302 f69bb0cc Baptiste Coudurier
static uint64_t max_bandwidth = 1000;
303 1ad8289e Baptiste Coudurier
static uint64_t current_bandwidth;
304 42a63c6a Philip Gladstone
305 c3f58185 Alex Beregszaszi
static int64_t cur_time;           // Making this global saves on passing it around everywhere
306 5eb765ef Philip Gladstone
307 1df93ae9 Alex Beregszaszi
static AVRandomState random_state;
308
309 85f07f22 Fabrice Bellard
static FILE *logfile = NULL;
310
311 9fd3442f Baptiste Coudurier
static char *ctime1(char *buf2)
312
{
313
    time_t ti;
314
    char *p;
315
316
    ti = time(NULL);
317
    p = ctime(&ti);
318
    strcpy(buf2, p);
319
    p = buf2 + strlen(p) - 1;
320
    if (*p == '\n')
321
        *p = '\0';
322
    return buf2;
323
}
324
325 bcd3ce59 Baptiste Coudurier
static void http_vlog(const char *fmt, va_list vargs)
326 85f07f22 Fabrice Bellard
{
327 124ed1c0 Baptiste Coudurier
    static int print_prefix = 1;
328 7434ba6d Philip Gladstone
    if (logfile) {
329 124ed1c0 Baptiste Coudurier
        if (print_prefix) {
330 9fd3442f Baptiste Coudurier
            char buf[32];
331
            ctime1(buf);
332
            fprintf(logfile, "%s ", buf);
333 124ed1c0 Baptiste Coudurier
        }
334
        print_prefix = strstr(fmt, "\n") != NULL;
335 bcd3ce59 Baptiste Coudurier
        vfprintf(logfile, fmt, vargs);
336 7434ba6d Philip Gladstone
        fflush(logfile);
337
    }
338 bcd3ce59 Baptiste Coudurier
}
339
340
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
341
{
342
    va_list vargs;
343
    va_start(vargs, fmt);
344
    http_vlog(fmt, vargs);
345
    va_end(vargs);
346
}
347
348
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
349
{
350
    static int print_prefix = 1;
351
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
352
    if (level > av_log_level)
353
        return;
354
    if (print_prefix && avc)
355 59e7894c Baptiste Coudurier
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
356 bcd3ce59 Baptiste Coudurier
    print_prefix = strstr(fmt, "\n") != NULL;
357
    http_vlog(fmt, vargs);
358 85f07f22 Fabrice Bellard
}
359
360 6edd6884 Fabrice Bellard
static void log_connection(HTTPContext *c)
361
{
362 115329f1 Diego Biurrun
    if (c->suppress_log)
363 6edd6884 Fabrice Bellard
        return;
364
365 82e0be62 Baptiste Coudurier
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
366
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
367 6edd6884 Fabrice Bellard
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
368 cde25790 Philip Gladstone
}
369
370 0c1a9eda Zdenek Kabelac
static void update_datarate(DataRateData *drd, int64_t count)
371 5eb765ef Philip Gladstone
{
372
    if (!drd->time1 && !drd->count1) {
373
        drd->time1 = drd->time2 = cur_time;
374
        drd->count1 = drd->count2 = count;
375 eeffbdea Alex Beregszaszi
    } else if (cur_time - drd->time2 > 5000) {
376 33a4ecbe Alex Beregszaszi
        drd->time1 = drd->time2;
377
        drd->count1 = drd->count2;
378
        drd->time2 = cur_time;
379
        drd->count2 = count;
380 5eb765ef Philip Gladstone
    }
381
}
382
383
/* In bytes per second */
384 0c1a9eda Zdenek Kabelac
static int compute_datarate(DataRateData *drd, int64_t count)
385 5eb765ef Philip Gladstone
{
386
    if (cur_time == drd->time1)
387
        return 0;
388 115329f1 Diego Biurrun
389 5eb765ef Philip Gladstone
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
390
}
391
392 a782f209 Philip Gladstone
393 cde25790 Philip Gladstone
static void start_children(FFStream *feed)
394
{
395 2ac887ba Philip Gladstone
    if (no_launch)
396
        return;
397
398 cde25790 Philip Gladstone
    for (; feed; feed = feed->next) {
399 5eb765ef Philip Gladstone
        if (feed->child_argv && !feed->pid) {
400
            feed->pid_start = time(0);
401
402 cde25790 Philip Gladstone
            feed->pid = fork();
403
404
            if (feed->pid < 0) {
405 b4befb99 Baptiste Coudurier
                http_log("Unable to create children\n");
406 cde25790 Philip Gladstone
                exit(1);
407
            }
408
            if (!feed->pid) {
409
                /* In child */
410
                char pathname[1024];
411
                char *slash;
412
                int i;
413
414 40444a59 Stefano Sabatini
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
415
416
                slash = strrchr(pathname, '/');
417
                if (!slash)
418
                    slash = pathname;
419
                else
420
                    slash++;
421
                strcpy(slash, "ffmpeg");
422
423 8bf61f5b Stefano Sabatini
                http_log("Launch commandline: ");
424
                http_log("%s ", pathname);
425
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
426
                    http_log("%s ", feed->child_argv[i]);
427
                http_log("\n");
428 40444a59 Stefano Sabatini
429 611c5741 Alex Beregszaszi
                for (i = 3; i < 256; i++)
430 5eb765ef Philip Gladstone
                    close(i);
431 cde25790 Philip Gladstone
432 5eb765ef Philip Gladstone
                if (!ffserver_debug) {
433 2ac887ba Philip Gladstone
                    i = open("/dev/null", O_RDWR);
434 3296409d Baptiste Coudurier
                    if (i != -1) {
435 2ac887ba Philip Gladstone
                        dup2(i, 0);
436 3296409d Baptiste Coudurier
                        dup2(i, 1);
437
                        dup2(i, 2);
438 5eb765ef Philip Gladstone
                        close(i);
439 3296409d Baptiste Coudurier
                    }
440 2ac887ba Philip Gladstone
                }
441 cde25790 Philip Gladstone
442 d6562d2c Philip Gladstone
                /* This is needed to make relative pathnames work */
443
                chdir(my_program_dir);
444
445 a4d70941 Philip Gladstone
                signal(SIGPIPE, SIG_DFL);
446
447 cde25790 Philip Gladstone
                execvp(pathname, feed->child_argv);
448
449
                _exit(1);
450
            }
451
        }
452
    }
453 7434ba6d Philip Gladstone
}
454
455 2effd274 Fabrice Bellard
/* open a listening socket */
456
static int socket_open_listen(struct sockaddr_in *my_addr)
457 85f07f22 Fabrice Bellard
{
458 2effd274 Fabrice Bellard
    int server_fd, tmp;
459 85f07f22 Fabrice Bellard
460
    server_fd = socket(AF_INET,SOCK_STREAM,0);
461
    if (server_fd < 0) {
462
        perror ("socket");
463
        return -1;
464
    }
465 115329f1 Diego Biurrun
466 85f07f22 Fabrice Bellard
    tmp = 1;
467
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
468
469 2effd274 Fabrice Bellard
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
470 b17d099d Philip Gladstone
        char bindmsg[32];
471
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
472
        perror (bindmsg);
473 d96633bb Alex Beregszaszi
        closesocket(server_fd);
474 85f07f22 Fabrice Bellard
        return -1;
475
    }
476 115329f1 Diego Biurrun
477 85f07f22 Fabrice Bellard
    if (listen (server_fd, 5) < 0) {
478
        perror ("listen");
479 d96633bb Alex Beregszaszi
        closesocket(server_fd);
480 85f07f22 Fabrice Bellard
        return -1;
481
    }
482 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(server_fd, 1);
483 2effd274 Fabrice Bellard
484
    return server_fd;
485
}
486
487 6edd6884 Fabrice Bellard
/* start all multicast streams */
488
static void start_multicast(void)
489
{
490
    FFStream *stream;
491
    char session_id[32];
492
    HTTPContext *rtp_c;
493
    struct sockaddr_in dest_addr;
494
    int default_port, stream_index;
495
496
    default_port = 6000;
497
    for(stream = first_stream; stream != NULL; stream = stream->next) {
498
        if (stream->is_multicast) {
499
            /* open the RTP connection */
500 1df93ae9 Alex Beregszaszi
            snprintf(session_id, sizeof(session_id), "%08x%08x",
501
                     av_random(&random_state), av_random(&random_state));
502 6edd6884 Fabrice Bellard
503
            /* choose a port if none given */
504
            if (stream->multicast_port == 0) {
505
                stream->multicast_port = default_port;
506
                default_port += 100;
507
            }
508
509
            dest_addr.sin_family = AF_INET;
510
            dest_addr.sin_addr = stream->multicast_ip;
511
            dest_addr.sin_port = htons(stream->multicast_port);
512
513 115329f1 Diego Biurrun
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
514 90abbdba Ronald S. Bultje
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
515 611c5741 Alex Beregszaszi
            if (!rtp_c)
516 6edd6884 Fabrice Bellard
                continue;
517 611c5741 Alex Beregszaszi
518 6edd6884 Fabrice Bellard
            if (open_input_stream(rtp_c, "") < 0) {
519 b4befb99 Baptiste Coudurier
                http_log("Could not open input stream for stream '%s'\n",
520
                         stream->filename);
521 6edd6884 Fabrice Bellard
                continue;
522
            }
523
524
            /* open each RTP stream */
525 115329f1 Diego Biurrun
            for(stream_index = 0; stream_index < stream->nb_streams;
526 6edd6884 Fabrice Bellard
                stream_index++) {
527 115329f1 Diego Biurrun
                dest_addr.sin_port = htons(stream->multicast_port +
528 6edd6884 Fabrice Bellard
                                           2 * stream_index);
529 bc351386 Fabrice Bellard
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
530 b4befb99 Baptiste Coudurier
                    http_log("Could not open output stream '%s/streamid=%d'\n",
531
                             stream->filename, stream_index);
532 0fa45e19 Fabrice Bellard
                    exit(1);
533 6edd6884 Fabrice Bellard
                }
534
            }
535
536
            /* change state to send data */
537
            rtp_c->state = HTTPSTATE_SEND_DATA;
538
        }
539
    }
540
}
541 2effd274 Fabrice Bellard
542
/* main loop of the http server */
543
static int http_server(void)
544
{
545 d2a1ea1d Baptiste Coudurier
    int server_fd = 0, rtsp_server_fd = 0;
546
    int ret, delay, delay1;
547 1c9ff179 Stefano Sabatini
    struct pollfd *poll_table, *poll_entry;
548 2effd274 Fabrice Bellard
    HTTPContext *c, *c_next;
549
550 a7f361eb Baptiste Coudurier
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
551 1c9ff179 Stefano Sabatini
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
552
        return -1;
553
    }
554
555 d2a1ea1d Baptiste Coudurier
    if (my_http_addr.sin_port) {
556 2b9cd1e7 Baptiste Coudurier
        server_fd = socket_open_listen(&my_http_addr);
557
        if (server_fd < 0)
558
            return -1;
559 d2a1ea1d Baptiste Coudurier
    }
560 85f07f22 Fabrice Bellard
561 d2a1ea1d Baptiste Coudurier
    if (my_rtsp_addr.sin_port) {
562 2b9cd1e7 Baptiste Coudurier
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
563
        if (rtsp_server_fd < 0)
564
            return -1;
565 d2a1ea1d Baptiste Coudurier
    }
566
567
    if (!rtsp_server_fd && !server_fd) {
568
        http_log("HTTP and RTSP disabled.\n");
569
        return -1;
570
    }
571 115329f1 Diego Biurrun
572 a3341b9d Baptiste Coudurier
    http_log("FFserver started.\n");
573 85f07f22 Fabrice Bellard
574 cde25790 Philip Gladstone
    start_children(first_feed);
575
576 6edd6884 Fabrice Bellard
    start_multicast();
577
578 85f07f22 Fabrice Bellard
    for(;;) {
579
        poll_entry = poll_table;
580 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
581 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = server_fd;
582
            poll_entry->events = POLLIN;
583
            poll_entry++;
584 d2a1ea1d Baptiste Coudurier
        }
585
        if (rtsp_server_fd) {
586 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = rtsp_server_fd;
587
            poll_entry->events = POLLIN;
588
            poll_entry++;
589 d2a1ea1d Baptiste Coudurier
        }
590 2effd274 Fabrice Bellard
591 85f07f22 Fabrice Bellard
        /* wait for events on each HTTP handle */
592
        c = first_http_ctx;
593 2effd274 Fabrice Bellard
        delay = 1000;
594 85f07f22 Fabrice Bellard
        while (c != NULL) {
595
            int fd;
596
            fd = c->fd;
597
            switch(c->state) {
598 2effd274 Fabrice Bellard
            case HTTPSTATE_SEND_HEADER:
599
            case RTSPSTATE_SEND_REPLY:
600 bc351386 Fabrice Bellard
            case RTSPSTATE_SEND_PACKET:
601 85f07f22 Fabrice Bellard
                c->poll_entry = poll_entry;
602
                poll_entry->fd = fd;
603 2effd274 Fabrice Bellard
                poll_entry->events = POLLOUT;
604 85f07f22 Fabrice Bellard
                poll_entry++;
605
                break;
606
            case HTTPSTATE_SEND_DATA_HEADER:
607
            case HTTPSTATE_SEND_DATA:
608
            case HTTPSTATE_SEND_DATA_TRAILER:
609 2effd274 Fabrice Bellard
                if (!c->is_packetized) {
610
                    /* for TCP, we output as much as we can (may need to put a limit) */
611
                    c->poll_entry = poll_entry;
612
                    poll_entry->fd = fd;
613
                    poll_entry->events = POLLOUT;
614
                    poll_entry++;
615
                } else {
616 e240a0bb Fabrice Bellard
                    /* when ffserver is doing the timing, we work by
617
                       looking at which packet need to be sent every
618
                       10 ms */
619
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
620
                    if (delay1 < delay)
621
                        delay = delay1;
622 2effd274 Fabrice Bellard
                }
623 85f07f22 Fabrice Bellard
                break;
624 2effd274 Fabrice Bellard
            case HTTPSTATE_WAIT_REQUEST:
625 85f07f22 Fabrice Bellard
            case HTTPSTATE_RECEIVE_DATA:
626
            case HTTPSTATE_WAIT_FEED:
627 2effd274 Fabrice Bellard
            case RTSPSTATE_WAIT_REQUEST:
628 85f07f22 Fabrice Bellard
                /* need to catch errors */
629
                c->poll_entry = poll_entry;
630
                poll_entry->fd = fd;
631 a6e14edd Philip Gladstone
                poll_entry->events = POLLIN;/* Maybe this will work */
632 85f07f22 Fabrice Bellard
                poll_entry++;
633
                break;
634
            default:
635
                c->poll_entry = NULL;
636
                break;
637
            }
638
            c = c->next;
639
        }
640
641
        /* wait for an event on one connection. We poll at least every
642
           second to handle timeouts */
643
        do {
644 2effd274 Fabrice Bellard
            ret = poll(poll_table, poll_entry - poll_table, delay);
645 8da4034f Alex Beregszaszi
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
646
                ff_neterrno() != FF_NETERROR(EINTR))
647 53e2f9ca Michael Niedermayer
                return -1;
648 e8d658df Luca Abeni
        } while (ret < 0);
649 115329f1 Diego Biurrun
650 c3f58185 Alex Beregszaszi
        cur_time = av_gettime() / 1000;
651 85f07f22 Fabrice Bellard
652 5eb765ef Philip Gladstone
        if (need_to_start_children) {
653
            need_to_start_children = 0;
654
            start_children(first_feed);
655
        }
656
657 85f07f22 Fabrice Bellard
        /* now handle the events */
658 2effd274 Fabrice Bellard
        for(c = first_http_ctx; c != NULL; c = c_next) {
659
            c_next = c->next;
660
            if (handle_connection(c) < 0) {
661 85f07f22 Fabrice Bellard
                /* close and free the connection */
662 7434ba6d Philip Gladstone
                log_connection(c);
663 2effd274 Fabrice Bellard
                close_connection(c);
664 85f07f22 Fabrice Bellard
            }
665
        }
666
667
        poll_entry = poll_table;
668 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
669 2b9cd1e7 Baptiste Coudurier
            /* new HTTP connection request ? */
670
            if (poll_entry->revents & POLLIN)
671
                new_connection(server_fd, 0);
672
            poll_entry++;
673 d2a1ea1d Baptiste Coudurier
        }
674
        if (rtsp_server_fd) {
675 2b9cd1e7 Baptiste Coudurier
            /* new RTSP connection request ? */
676
            if (poll_entry->revents & POLLIN)
677
                new_connection(rtsp_server_fd, 1);
678 d2a1ea1d Baptiste Coudurier
        }
679 85f07f22 Fabrice Bellard
    }
680
}
681
682 2effd274 Fabrice Bellard
/* start waiting for a new HTTP/RTSP request */
683
static void start_wait_request(HTTPContext *c, int is_rtsp)
684 85f07f22 Fabrice Bellard
{
685 2effd274 Fabrice Bellard
    c->buffer_ptr = c->buffer;
686
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
687
688
    if (is_rtsp) {
689
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
690
        c->state = RTSPSTATE_WAIT_REQUEST;
691
    } else {
692
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
693
        c->state = HTTPSTATE_WAIT_REQUEST;
694
    }
695
}
696
697
static void new_connection(int server_fd, int is_rtsp)
698
{
699
    struct sockaddr_in from_addr;
700
    int fd, len;
701
    HTTPContext *c = NULL;
702
703
    len = sizeof(from_addr);
704 115329f1 Diego Biurrun
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
705 2effd274 Fabrice Bellard
                &len);
706 050056d0 Baptiste Coudurier
    if (fd < 0) {
707
        http_log("error during accept %s\n", strerror(errno));
708 2effd274 Fabrice Bellard
        return;
709 050056d0 Baptiste Coudurier
    }
710 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(fd, 1);
711 2effd274 Fabrice Bellard
712
    /* XXX: should output a warning page when coming
713
       close to the connection limit */
714
    if (nb_connections >= nb_max_connections)
715
        goto fail;
716 115329f1 Diego Biurrun
717 2effd274 Fabrice Bellard
    /* add a new connection */
718
    c = av_mallocz(sizeof(HTTPContext));
719
    if (!c)
720
        goto fail;
721 115329f1 Diego Biurrun
722 2effd274 Fabrice Bellard
    c->fd = fd;
723
    c->poll_entry = NULL;
724
    c->from_addr = from_addr;
725
    c->buffer_size = IOBUFFER_INIT_SIZE;
726
    c->buffer = av_malloc(c->buffer_size);
727
    if (!c->buffer)
728
        goto fail;
729 8bc80f8b Philip Gladstone
730
    c->next = first_http_ctx;
731
    first_http_ctx = c;
732 2effd274 Fabrice Bellard
    nb_connections++;
733 115329f1 Diego Biurrun
734 2effd274 Fabrice Bellard
    start_wait_request(c, is_rtsp);
735
736
    return;
737
738
 fail:
739
    if (c) {
740
        av_free(c->buffer);
741
        av_free(c);
742
    }
743 d96633bb Alex Beregszaszi
    closesocket(fd);
744 2effd274 Fabrice Bellard
}
745
746
static void close_connection(HTTPContext *c)
747
{
748
    HTTPContext **cp, *c1;
749
    int i, nb_streams;
750
    AVFormatContext *ctx;
751
    URLContext *h;
752
    AVStream *st;
753
754
    /* remove connection from list */
755
    cp = &first_http_ctx;
756
    while ((*cp) != NULL) {
757
        c1 = *cp;
758 611c5741 Alex Beregszaszi
        if (c1 == c)
759 2effd274 Fabrice Bellard
            *cp = c->next;
760 611c5741 Alex Beregszaszi
        else
761 2effd274 Fabrice Bellard
            cp = &c1->next;
762
    }
763
764 bc351386 Fabrice Bellard
    /* remove references, if any (XXX: do it faster) */
765
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
766
        if (c1->rtsp_c == c)
767
            c1->rtsp_c = NULL;
768
    }
769
770 2effd274 Fabrice Bellard
    /* remove connection associated resources */
771
    if (c->fd >= 0)
772 d96633bb Alex Beregszaszi
        closesocket(c->fd);
773 2effd274 Fabrice Bellard
    if (c->fmt_in) {
774
        /* close each frame parser */
775
        for(i=0;i<c->fmt_in->nb_streams;i++) {
776
            st = c->fmt_in->streams[i];
777 611c5741 Alex Beregszaszi
            if (st->codec->codec)
778 01f4895c Michael Niedermayer
                avcodec_close(st->codec);
779 2effd274 Fabrice Bellard
        }
780
        av_close_input_file(c->fmt_in);
781
    }
782
783
    /* free RTP output streams if any */
784
    nb_streams = 0;
785 115329f1 Diego Biurrun
    if (c->stream)
786 2effd274 Fabrice Bellard
        nb_streams = c->stream->nb_streams;
787 115329f1 Diego Biurrun
788 2effd274 Fabrice Bellard
    for(i=0;i<nb_streams;i++) {
789
        ctx = c->rtp_ctx[i];
790
        if (ctx) {
791
            av_write_trailer(ctx);
792
            av_free(ctx);
793
        }
794
        h = c->rtp_handles[i];
795 611c5741 Alex Beregszaszi
        if (h)
796 2effd274 Fabrice Bellard
            url_close(h);
797
    }
798 115329f1 Diego Biurrun
799 b88ba823 Mark Hills
    ctx = &c->fmt_ctx;
800
801 637b638e Baptiste Coudurier
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
802 87638494 Philip Gladstone
        if (ctx->oformat) {
803
            /* prepare header */
804
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
805
                av_write_trailer(ctx);
806 f8b06be9 Baptiste Coudurier
                av_freep(&c->pb_buffer);
807 899681cd Björn Axelsson
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
808 87638494 Philip Gladstone
            }
809
        }
810
    }
811
812 115329f1 Diego Biurrun
    for(i=0; i<ctx->nb_streams; i++)
813 0bd53967 Alex Beregszaszi
        av_free(ctx->streams[i]);
814 f0ef6240 Philip Gladstone
815 edfdd798 Alex Beregszaszi
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
816 6edd6884 Fabrice Bellard
        current_bandwidth -= c->stream->bandwidth;
817 5400e092 Alex Beregszaszi
818
    /* signal that there is no feed if we are the feeder socket */
819
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
820
        c->stream->feed_opened = 0;
821
        close(c->feed_fd);
822
    }
823
824 2effd274 Fabrice Bellard
    av_freep(&c->pb_buffer);
825 bc351386 Fabrice Bellard
    av_freep(&c->packet_buffer);
826 2effd274 Fabrice Bellard
    av_free(c->buffer);
827
    av_free(c);
828
    nb_connections--;
829
}
830
831
static int handle_connection(HTTPContext *c)
832
{
833
    int len, ret;
834 115329f1 Diego Biurrun
835 85f07f22 Fabrice Bellard
    switch(c->state) {
836
    case HTTPSTATE_WAIT_REQUEST:
837 2effd274 Fabrice Bellard
    case RTSPSTATE_WAIT_REQUEST:
838 85f07f22 Fabrice Bellard
        /* timeout ? */
839
        if ((c->timeout - cur_time) < 0)
840
            return -1;
841
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
842
            return -1;
843
844
        /* no need to read if no events */
845
        if (!(c->poll_entry->revents & POLLIN))
846
            return 0;
847
        /* read the data */
848 1bc1cfdd Giancarlo Formicuccia
    read_loop:
849 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, 1, 0);
850 85f07f22 Fabrice Bellard
        if (len < 0) {
851 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
852
                ff_neterrno() != FF_NETERROR(EINTR))
853 85f07f22 Fabrice Bellard
                return -1;
854
        } else if (len == 0) {
855
            return -1;
856
        } else {
857 94d9ad5f Giancarlo Formicuccia
            /* search for end of request. */
858 0c1a9eda Zdenek Kabelac
            uint8_t *ptr;
859 85f07f22 Fabrice Bellard
            c->buffer_ptr += len;
860
            ptr = c->buffer_ptr;
861
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
862
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
863
                /* request found : parse it and reply */
864 2effd274 Fabrice Bellard
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
865
                    ret = http_parse_request(c);
866
                } else {
867
                    ret = rtsp_parse_request(c);
868
                }
869
                if (ret < 0)
870 85f07f22 Fabrice Bellard
                    return -1;
871
            } else if (ptr >= c->buffer_end) {
872
                /* request too long: cannot do anything */
873
                return -1;
874 1bc1cfdd Giancarlo Formicuccia
            } else goto read_loop;
875 85f07f22 Fabrice Bellard
        }
876
        break;
877
878
    case HTTPSTATE_SEND_HEADER:
879
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
880
            return -1;
881
882 2effd274 Fabrice Bellard
        /* no need to write if no events */
883 85f07f22 Fabrice Bellard
        if (!(c->poll_entry->revents & POLLOUT))
884
            return 0;
885 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
886 85f07f22 Fabrice Bellard
        if (len < 0) {
887 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
888
                ff_neterrno() != FF_NETERROR(EINTR)) {
889 85f07f22 Fabrice Bellard
                /* error : close connection */
890 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
891 85f07f22 Fabrice Bellard
                return -1;
892
            }
893
        } else {
894
            c->buffer_ptr += len;
895 2e04edb3 Philip Gladstone
            if (c->stream)
896
                c->stream->bytes_served += len;
897 a6e14edd Philip Gladstone
            c->data_count += len;
898 85f07f22 Fabrice Bellard
            if (c->buffer_ptr >= c->buffer_end) {
899 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
900 85f07f22 Fabrice Bellard
                /* if error, exit */
901 611c5741 Alex Beregszaszi
                if (c->http_error)
902 85f07f22 Fabrice Bellard
                    return -1;
903 2effd274 Fabrice Bellard
                /* all the buffer was sent : synchronize to the incoming stream */
904 85f07f22 Fabrice Bellard
                c->state = HTTPSTATE_SEND_DATA_HEADER;
905
                c->buffer_ptr = c->buffer_end = c->buffer;
906
            }
907
        }
908
        break;
909
910
    case HTTPSTATE_SEND_DATA:
911
    case HTTPSTATE_SEND_DATA_HEADER:
912
    case HTTPSTATE_SEND_DATA_TRAILER:
913 2effd274 Fabrice Bellard
        /* for packetized output, we consider we can always write (the
914
           input streams sets the speed). It may be better to verify
915
           that we do not rely too much on the kernel queues */
916
        if (!c->is_packetized) {
917
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
918
                return -1;
919 115329f1 Diego Biurrun
920 2effd274 Fabrice Bellard
            /* no need to read if no events */
921
            if (!(c->poll_entry->revents & POLLOUT))
922
                return 0;
923
        }
924 5eb765ef Philip Gladstone
        if (http_send_data(c) < 0)
925 85f07f22 Fabrice Bellard
            return -1;
926 638831aa Alex Beregszaszi
        /* close connection if trailer sent */
927
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
928
            return -1;
929 85f07f22 Fabrice Bellard
        break;
930
    case HTTPSTATE_RECEIVE_DATA:
931
        /* no need to read if no events */
932
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
933
            return -1;
934
        if (!(c->poll_entry->revents & POLLIN))
935
            return 0;
936
        if (http_receive_data(c) < 0)
937
            return -1;
938
        break;
939
    case HTTPSTATE_WAIT_FEED:
940
        /* no need to read if no events */
941 a6e14edd Philip Gladstone
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
942 85f07f22 Fabrice Bellard
            return -1;
943
944
        /* nothing to do, we'll be waken up by incoming feed packets */
945
        break;
946 2effd274 Fabrice Bellard
947
    case RTSPSTATE_SEND_REPLY:
948
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
949
            av_freep(&c->pb_buffer);
950
            return -1;
951
        }
952
        /* no need to write if no events */
953
        if (!(c->poll_entry->revents & POLLOUT))
954
            return 0;
955 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
956 2effd274 Fabrice Bellard
        if (len < 0) {
957 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
958
                ff_neterrno() != FF_NETERROR(EINTR)) {
959 2effd274 Fabrice Bellard
                /* error : close connection */
960
                av_freep(&c->pb_buffer);
961
                return -1;
962
            }
963
        } else {
964
            c->buffer_ptr += len;
965
            c->data_count += len;
966
            if (c->buffer_ptr >= c->buffer_end) {
967
                /* all the buffer was sent : wait for a new request */
968
                av_freep(&c->pb_buffer);
969
                start_wait_request(c, 1);
970
            }
971
        }
972
        break;
973 bc351386 Fabrice Bellard
    case RTSPSTATE_SEND_PACKET:
974
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
975
            av_freep(&c->packet_buffer);
976
            return -1;
977
        }
978
        /* no need to write if no events */
979
        if (!(c->poll_entry->revents & POLLOUT))
980
            return 0;
981 c60202df Alex Beregszaszi
        len = send(c->fd, c->packet_buffer_ptr,
982
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
983 bc351386 Fabrice Bellard
        if (len < 0) {
984 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
985
                ff_neterrno() != FF_NETERROR(EINTR)) {
986 bc351386 Fabrice Bellard
                /* error : close connection */
987
                av_freep(&c->packet_buffer);
988
                return -1;
989
            }
990
        } else {
991
            c->packet_buffer_ptr += len;
992
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
993
                /* all the buffer was sent : wait for a new request */
994
                av_freep(&c->packet_buffer);
995
                c->state = RTSPSTATE_WAIT_REQUEST;
996
            }
997
        }
998
        break;
999 2effd274 Fabrice Bellard
    case HTTPSTATE_READY:
1000
        /* nothing to do */
1001
        break;
1002 85f07f22 Fabrice Bellard
    default:
1003
        return -1;
1004
    }
1005
    return 0;
1006
}
1007
1008 3120d2a2 Philip Gladstone
static int extract_rates(char *rates, int ratelen, const char *request)
1009
{
1010
    const char *p;
1011
1012
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1013
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1014
            const char *q = p + 7;
1015
1016
            while (*q && *q != '\n' && isspace(*q))
1017
                q++;
1018
1019
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1020
                int stream_no;
1021
                int rate_no;
1022
1023
                q += 20;
1024
1025 cde25790 Philip Gladstone
                memset(rates, 0xff, ratelen);
1026 3120d2a2 Philip Gladstone
1027
                while (1) {
1028
                    while (*q && *q != '\n' && *q != ':')
1029
                        q++;
1030
1031 611c5741 Alex Beregszaszi
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1032 3120d2a2 Philip Gladstone
                        break;
1033 611c5741 Alex Beregszaszi
1034 3120d2a2 Philip Gladstone
                    stream_no--;
1035 611c5741 Alex Beregszaszi
                    if (stream_no < ratelen && stream_no >= 0)
1036 3120d2a2 Philip Gladstone
                        rates[stream_no] = rate_no;
1037
1038
                    while (*q && *q != '\n' && !isspace(*q))
1039
                        q++;
1040
                }
1041
1042
                return 1;
1043
            }
1044
        }
1045
        p = strchr(p, '\n');
1046
        if (!p)
1047
            break;
1048
1049
        p++;
1050
    }
1051
1052
    return 0;
1053
}
1054
1055 cde25790 Philip Gladstone
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1056 3120d2a2 Philip Gladstone
{
1057
    int i;
1058 cde25790 Philip Gladstone
    int best_bitrate = 100000000;
1059
    int best = -1;
1060
1061
    for (i = 0; i < feed->nb_streams; i++) {
1062 01f4895c Michael Niedermayer
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1063 cde25790 Philip Gladstone
1064
        if (feed_codec->codec_id != codec->codec_id ||
1065
            feed_codec->sample_rate != codec->sample_rate ||
1066
            feed_codec->width != codec->width ||
1067 611c5741 Alex Beregszaszi
            feed_codec->height != codec->height)
1068 cde25790 Philip Gladstone
            continue;
1069
1070
        /* Potential stream */
1071
1072 115329f1 Diego Biurrun
        /* We want the fastest stream less than bit_rate, or the slowest
1073 cde25790 Philip Gladstone
         * faster than bit_rate
1074
         */
1075
1076
        if (feed_codec->bit_rate <= bit_rate) {
1077
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1078
                best_bitrate = feed_codec->bit_rate;
1079
                best = i;
1080
            }
1081
        } else {
1082
            if (feed_codec->bit_rate < best_bitrate) {
1083
                best_bitrate = feed_codec->bit_rate;
1084
                best = i;
1085
            }
1086
        }
1087
    }
1088
1089
    return best;
1090
}
1091
1092
static int modify_current_stream(HTTPContext *c, char *rates)
1093
{
1094
    int i;
1095
    FFStream *req = c->stream;
1096
    int action_required = 0;
1097 3120d2a2 Philip Gladstone
1098 001bcd29 Philip Gladstone
    /* Not much we can do for a feed */
1099
    if (!req->feed)
1100
        return 0;
1101
1102 3120d2a2 Philip Gladstone
    for (i = 0; i < req->nb_streams; i++) {
1103 01f4895c Michael Niedermayer
        AVCodecContext *codec = req->streams[i]->codec;
1104 3120d2a2 Philip Gladstone
1105
        switch(rates[i]) {
1106
            case 0:
1107 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = req->feed_streams[i];
1108 3120d2a2 Philip Gladstone
                break;
1109
            case 1:
1110 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1111 3120d2a2 Philip Gladstone
                break;
1112
            case 2:
1113 cde25790 Philip Gladstone
                /* Wants off or slow */
1114
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1115
#ifdef WANTS_OFF
1116
                /* This doesn't work well when it turns off the only stream! */
1117
                c->switch_feed_streams[i] = -2;
1118
                c->feed_streams[i] = -2;
1119
#endif
1120 3120d2a2 Philip Gladstone
                break;
1121
        }
1122
1123 cde25790 Philip Gladstone
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1124
            action_required = 1;
1125
    }
1126 3120d2a2 Philip Gladstone
1127 cde25790 Philip Gladstone
    return action_required;
1128
}
1129 3120d2a2 Philip Gladstone
1130
1131 cde25790 Philip Gladstone
static void do_switch_stream(HTTPContext *c, int i)
1132
{
1133
    if (c->switch_feed_streams[i] >= 0) {
1134 115329f1 Diego Biurrun
#ifdef PHILIP
1135 cde25790 Philip Gladstone
        c->feed_streams[i] = c->switch_feed_streams[i];
1136
#endif
1137 3120d2a2 Philip Gladstone
1138 cde25790 Philip Gladstone
        /* Now update the stream */
1139 3120d2a2 Philip Gladstone
    }
1140 cde25790 Philip Gladstone
    c->switch_feed_streams[i] = -1;
1141 3120d2a2 Philip Gladstone
}
1142 7434ba6d Philip Gladstone
1143 2effd274 Fabrice Bellard
/* XXX: factorize in utils.c ? */
1144
/* XXX: take care with different space meaning */
1145
static void skip_spaces(const char **pp)
1146
{
1147
    const char *p;
1148
    p = *pp;
1149
    while (*p == ' ' || *p == '\t')
1150
        p++;
1151
    *pp = p;
1152
}
1153
1154
static void get_word(char *buf, int buf_size, const char **pp)
1155
{
1156
    const char *p;
1157
    char *q;
1158
1159
    p = *pp;
1160
    skip_spaces(&p);
1161
    q = buf;
1162
    while (!isspace(*p) && *p != '\0') {
1163
        if ((q - buf) < buf_size - 1)
1164
            *q++ = *p;
1165
        p++;
1166
    }
1167
    if (buf_size > 0)
1168
        *q = '\0';
1169
    *pp = p;
1170
}
1171
1172 8256c0a3 Philip Gladstone
static int validate_acl(FFStream *stream, HTTPContext *c)
1173
{
1174
    enum IPAddressAction last_action = IP_DENY;
1175
    IPAddressACL *acl;
1176
    struct in_addr *src = &c->from_addr.sin_addr;
1177 2bd8416e Alex Beregszaszi
    unsigned long src_addr = src->s_addr;
1178 8256c0a3 Philip Gladstone
1179
    for (acl = stream->acl; acl; acl = acl->next) {
1180 611c5741 Alex Beregszaszi
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1181 8256c0a3 Philip Gladstone
            return (acl->action == IP_ALLOW) ? 1 : 0;
1182
        last_action = acl->action;
1183
    }
1184
1185
    /* Nothing matched, so return not the last action */
1186
    return (last_action == IP_DENY) ? 1 : 0;
1187
}
1188
1189 829ac53d Fabrice Bellard
/* compute the real filename of a file by matching it without its
1190
   extensions to all the stream filenames */
1191
static void compute_real_filename(char *filename, int max_size)
1192
{
1193
    char file1[1024];
1194
    char file2[1024];
1195
    char *p;
1196
    FFStream *stream;
1197
1198
    /* compute filename by matching without the file extensions */
1199 f7d78f36 Måns Rullgård
    av_strlcpy(file1, filename, sizeof(file1));
1200 829ac53d Fabrice Bellard
    p = strrchr(file1, '.');
1201
    if (p)
1202
        *p = '\0';
1203
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1204 f7d78f36 Måns Rullgård
        av_strlcpy(file2, stream->filename, sizeof(file2));
1205 829ac53d Fabrice Bellard
        p = strrchr(file2, '.');
1206
        if (p)
1207
            *p = '\0';
1208
        if (!strcmp(file1, file2)) {
1209 f7d78f36 Måns Rullgård
            av_strlcpy(filename, stream->filename, max_size);
1210 829ac53d Fabrice Bellard
            break;
1211
        }
1212
    }
1213
}
1214
1215
enum RedirType {
1216
    REDIR_NONE,
1217
    REDIR_ASX,
1218
    REDIR_RAM,
1219
    REDIR_ASF,
1220
    REDIR_RTSP,
1221
    REDIR_SDP,
1222
};
1223
1224 85f07f22 Fabrice Bellard
/* parse http request and prepare header */
1225
static int http_parse_request(HTTPContext *c)
1226
{
1227
    char *p;
1228 829ac53d Fabrice Bellard
    enum RedirType redir_type;
1229 85f07f22 Fabrice Bellard
    char cmd[32];
1230 bae79c04 Alex Beregszaszi
    char info[1024], filename[1024];
1231 85f07f22 Fabrice Bellard
    char url[1024], *q;
1232
    char protocol[32];
1233
    char msg[1024];
1234
    const char *mime_type;
1235
    FFStream *stream;
1236 42a63c6a Philip Gladstone
    int i;
1237 3120d2a2 Philip Gladstone
    char ratebuf[32];
1238 cde25790 Philip Gladstone
    char *useragent = 0;
1239 85f07f22 Fabrice Bellard
1240
    p = c->buffer;
1241 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), (const char **)&p);
1242 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
1243 7434ba6d Philip Gladstone
1244 85f07f22 Fabrice Bellard
    if (!strcmp(cmd, "GET"))
1245 edfdd798 Alex Beregszaszi
        c->post = 0;
1246 85f07f22 Fabrice Bellard
    else if (!strcmp(cmd, "POST"))
1247 edfdd798 Alex Beregszaszi
        c->post = 1;
1248 85f07f22 Fabrice Bellard
    else
1249
        return -1;
1250
1251 2effd274 Fabrice Bellard
    get_word(url, sizeof(url), (const char **)&p);
1252 f7d78f36 Måns Rullgård
    av_strlcpy(c->url, url, sizeof(c->url));
1253 7434ba6d Philip Gladstone
1254 2effd274 Fabrice Bellard
    get_word(protocol, sizeof(protocol), (const char **)&p);
1255 85f07f22 Fabrice Bellard
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1256
        return -1;
1257 7434ba6d Philip Gladstone
1258 f7d78f36 Måns Rullgård
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1259 90f9c440 Alex Beregszaszi
1260
    if (ffserver_debug)
1261 bb270c08 Diego Biurrun
        http_log("New connection: %s %s\n", cmd, url);
1262 115329f1 Diego Biurrun
1263 85f07f22 Fabrice Bellard
    /* find the filename and the optional info string in the request */
1264 bae79c04 Alex Beregszaszi
    p = strchr(url, '?');
1265 85f07f22 Fabrice Bellard
    if (p) {
1266 f7d78f36 Måns Rullgård
        av_strlcpy(info, p, sizeof(info));
1267 85f07f22 Fabrice Bellard
        *p = '\0';
1268 611c5741 Alex Beregszaszi
    } else
1269 85f07f22 Fabrice Bellard
        info[0] = '\0';
1270
1271 f7d78f36 Måns Rullgård
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1272 bae79c04 Alex Beregszaszi
1273 cde25790 Philip Gladstone
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1274
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1275
            useragent = p + 11;
1276
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1277
                useragent++;
1278
            break;
1279
        }
1280
        p = strchr(p, '\n');
1281
        if (!p)
1282
            break;
1283
1284
        p++;
1285
    }
1286
1287 829ac53d Fabrice Bellard
    redir_type = REDIR_NONE;
1288
    if (match_ext(filename, "asx")) {
1289
        redir_type = REDIR_ASX;
1290 7434ba6d Philip Gladstone
        filename[strlen(filename)-1] = 'f';
1291 c2ce254c Philip Gladstone
    } else if (match_ext(filename, "asf") &&
1292 cde25790 Philip Gladstone
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1293
        /* if this isn't WMP or lookalike, return the redirector file */
1294 829ac53d Fabrice Bellard
        redir_type = REDIR_ASF;
1295
    } else if (match_ext(filename, "rpm,ram")) {
1296
        redir_type = REDIR_RAM;
1297 42a63c6a Philip Gladstone
        strcpy(filename + strlen(filename)-2, "m");
1298 829ac53d Fabrice Bellard
    } else if (match_ext(filename, "rtsp")) {
1299
        redir_type = REDIR_RTSP;
1300 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1301 829ac53d Fabrice Bellard
    } else if (match_ext(filename, "sdp")) {
1302
        redir_type = REDIR_SDP;
1303 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1304 42a63c6a Philip Gladstone
    }
1305 115329f1 Diego Biurrun
1306 bae79c04 Alex Beregszaszi
    // "redirect" / request to index.html
1307
    if (!strlen(filename))
1308 f7d78f36 Måns Rullgård
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1309 bae79c04 Alex Beregszaszi
1310 85f07f22 Fabrice Bellard
    stream = first_stream;
1311
    while (stream != NULL) {
1312 8256c0a3 Philip Gladstone
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1313 85f07f22 Fabrice Bellard
            break;
1314
        stream = stream->next;
1315
    }
1316
    if (stream == NULL) {
1317 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1318 85f07f22 Fabrice Bellard
        goto send_error;
1319
    }
1320 42a63c6a Philip Gladstone
1321 cde25790 Philip Gladstone
    c->stream = stream;
1322
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1323
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1324
1325
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1326
        c->http_error = 301;
1327
        q = c->buffer;
1328 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1329
                      "HTTP/1.0 301 Moved\r\n"
1330
                      "Location: %s\r\n"
1331
                      "Content-type: text/html\r\n"
1332
                      "\r\n"
1333
                      "<html><head><title>Moved</title></head><body>\r\n"
1334
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1335
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1336 cde25790 Philip Gladstone
        /* prepare output buffer */
1337
        c->buffer_ptr = c->buffer;
1338
        c->buffer_end = q;
1339
        c->state = HTTPSTATE_SEND_HEADER;
1340
        return 0;
1341
    }
1342
1343 3120d2a2 Philip Gladstone
    /* If this is WMP, get the rate information */
1344
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1345 cde25790 Philip Gladstone
        if (modify_current_stream(c, ratebuf)) {
1346 37d3e066 Aurelien Jacobs
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1347 cde25790 Philip Gladstone
                if (c->switch_feed_streams[i] >= 0)
1348
                    do_switch_stream(c, i);
1349
            }
1350
        }
1351 3120d2a2 Philip Gladstone
    }
1352
1353 755bfeab Diego Biurrun
    /* If already streaming this feed, do not let start another feeder. */
1354 d0a5513b Alex Beregszaszi
    if (stream->feed_opened) {
1355
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1356 14c43f91 Baptiste Coudurier
        http_log("feed %s already being received\n", stream->feed_filename);
1357 d0a5513b Alex Beregszaszi
        goto send_error;
1358
    }
1359
1360 611c5741 Alex Beregszaszi
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1361 6edd6884 Fabrice Bellard
        current_bandwidth += stream->bandwidth;
1362 115329f1 Diego Biurrun
1363 edfdd798 Alex Beregszaszi
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1364 42a63c6a Philip Gladstone
        c->http_error = 200;
1365
        q = c->buffer;
1366 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1367
                      "HTTP/1.0 200 Server too busy\r\n"
1368
                      "Content-type: text/html\r\n"
1369
                      "\r\n"
1370
                      "<html><head><title>Too busy</title></head><body>\r\n"
1371
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1372 0be4b8d9 Baptiste Coudurier
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1373
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1374 a3aa4fed Baptiste Coudurier
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1375 42a63c6a Philip Gladstone
        /* prepare output buffer */
1376
        c->buffer_ptr = c->buffer;
1377
        c->buffer_end = q;
1378
        c->state = HTTPSTATE_SEND_HEADER;
1379
        return 0;
1380
    }
1381 115329f1 Diego Biurrun
1382 829ac53d Fabrice Bellard
    if (redir_type != REDIR_NONE) {
1383 7434ba6d Philip Gladstone
        char *hostinfo = 0;
1384 115329f1 Diego Biurrun
1385 7434ba6d Philip Gladstone
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1386
            if (strncasecmp(p, "Host:", 5) == 0) {
1387
                hostinfo = p + 5;
1388
                break;
1389
            }
1390
            p = strchr(p, '\n');
1391
            if (!p)
1392
                break;
1393
1394
            p++;
1395
        }
1396
1397
        if (hostinfo) {
1398
            char *eoh;
1399
            char hostbuf[260];
1400
1401
            while (isspace(*hostinfo))
1402
                hostinfo++;
1403
1404
            eoh = strchr(hostinfo, '\n');
1405
            if (eoh) {
1406
                if (eoh[-1] == '\r')
1407
                    eoh--;
1408
1409
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1410
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1411
                    hostbuf[eoh - hostinfo] = 0;
1412
1413
                    c->http_error = 200;
1414
                    q = c->buffer;
1415 829ac53d Fabrice Bellard
                    switch(redir_type) {
1416
                    case REDIR_ASX:
1417 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1418
                                      "HTTP/1.0 200 ASX Follows\r\n"
1419
                                      "Content-type: video/x-ms-asf\r\n"
1420
                                      "\r\n"
1421
                                      "<ASX Version=\"3\">\r\n"
1422
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1423
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1424
                                      "</ASX>\r\n", hostbuf, filename, info);
1425 829ac53d Fabrice Bellard
                        break;
1426
                    case REDIR_RAM:
1427 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1428
                                      "HTTP/1.0 200 RAM Follows\r\n"
1429
                                      "Content-type: audio/x-pn-realaudio\r\n"
1430
                                      "\r\n"
1431
                                      "# Autogenerated by ffserver\r\n"
1432
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1433 829ac53d Fabrice Bellard
                        break;
1434
                    case REDIR_ASF:
1435 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1436
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1437
                                      "Content-type: video/x-ms-asf\r\n"
1438
                                      "\r\n"
1439
                                      "[Reference]\r\n"
1440
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1441 829ac53d Fabrice Bellard
                        break;
1442
                    case REDIR_RTSP:
1443
                        {
1444
                            char hostname[256], *p;
1445
                            /* extract only hostname */
1446 f7d78f36 Måns Rullgård
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1447 829ac53d Fabrice Bellard
                            p = strrchr(hostname, ':');
1448
                            if (p)
1449
                                *p = '\0';
1450 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1451
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1452
                                          /* XXX: incorrect mime type ? */
1453
                                          "Content-type: application/x-rtsp\r\n"
1454
                                          "\r\n"
1455
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1456 829ac53d Fabrice Bellard
                        }
1457
                        break;
1458
                    case REDIR_SDP:
1459
                        {
1460 0c1a9eda Zdenek Kabelac
                            uint8_t *sdp_data;
1461 829ac53d Fabrice Bellard
                            int sdp_data_size, len;
1462
                            struct sockaddr_in my_addr;
1463
1464 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1465
                                          "HTTP/1.0 200 OK\r\n"
1466
                                          "Content-type: application/sdp\r\n"
1467
                                          "\r\n");
1468 829ac53d Fabrice Bellard
1469
                            len = sizeof(my_addr);
1470
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1471 115329f1 Diego Biurrun
1472 829ac53d Fabrice Bellard
                            /* XXX: should use a dynamic buffer */
1473 115329f1 Diego Biurrun
                            sdp_data_size = prepare_sdp_description(stream,
1474
                                                                    &sdp_data,
1475 829ac53d Fabrice Bellard
                                                                    my_addr.sin_addr);
1476
                            if (sdp_data_size > 0) {
1477
                                memcpy(q, sdp_data, sdp_data_size);
1478
                                q += sdp_data_size;
1479
                                *q = '\0';
1480
                                av_free(sdp_data);
1481
                            }
1482
                        }
1483
                        break;
1484
                    default:
1485 0f4e8165 Ronald S. Bultje
                        abort();
1486 829ac53d Fabrice Bellard
                        break;
1487 2effd274 Fabrice Bellard
                    }
1488 7434ba6d Philip Gladstone
1489
                    /* prepare output buffer */
1490
                    c->buffer_ptr = c->buffer;
1491
                    c->buffer_end = q;
1492
                    c->state = HTTPSTATE_SEND_HEADER;
1493
                    return 0;
1494
                }
1495
            }
1496
        }
1497
1498 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1499 7434ba6d Philip Gladstone
        goto send_error;
1500 85f07f22 Fabrice Bellard
    }
1501
1502 a6e14edd Philip Gladstone
    stream->conns_served++;
1503 7434ba6d Philip Gladstone
1504 85f07f22 Fabrice Bellard
    /* XXX: add there authenticate and IP match */
1505
1506 edfdd798 Alex Beregszaszi
    if (c->post) {
1507 85f07f22 Fabrice Bellard
        /* if post, it means a feed is being sent */
1508
        if (!stream->is_feed) {
1509 e16190fa Diego Biurrun
            /* However it might be a status report from WMP! Let us log the
1510
             * data as it might come in handy one day. */
1511 7434ba6d Philip Gladstone
            char *logline = 0;
1512 3120d2a2 Philip Gladstone
            int client_id = 0;
1513 115329f1 Diego Biurrun
1514 7434ba6d Philip Gladstone
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1515
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1516
                    logline = p;
1517
                    break;
1518
                }
1519 611c5741 Alex Beregszaszi
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1520 3120d2a2 Philip Gladstone
                    client_id = strtol(p + 18, 0, 10);
1521 7434ba6d Philip Gladstone
                p = strchr(p, '\n');
1522
                if (!p)
1523
                    break;
1524
1525
                p++;
1526
            }
1527
1528
            if (logline) {
1529
                char *eol = strchr(logline, '\n');
1530
1531
                logline += 17;
1532
1533
                if (eol) {
1534
                    if (eol[-1] == '\r')
1535
                        eol--;
1536 7906085f Falk Hüffner
                    http_log("%.*s\n", (int) (eol - logline), logline);
1537 7434ba6d Philip Gladstone
                    c->suppress_log = 1;
1538
                }
1539
            }
1540 3120d2a2 Philip Gladstone
1541 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1542
            http_log("\nGot request:\n%s\n", c->buffer);
1543 3120d2a2 Philip Gladstone
#endif
1544
1545
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1546
                HTTPContext *wmpc;
1547
1548
                /* Now we have to find the client_id */
1549
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1550
                    if (wmpc->wmp_client_id == client_id)
1551
                        break;
1552
                }
1553
1554 2d563d2f Alex Beregszaszi
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1555
                    wmpc->switch_pending = 1;
1556 3120d2a2 Philip Gladstone
            }
1557 115329f1 Diego Biurrun
1558 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "POST command not handled");
1559 cb275dd9 Philip Gladstone
            c->stream = 0;
1560 85f07f22 Fabrice Bellard
            goto send_error;
1561
        }
1562
        if (http_start_receive_data(c) < 0) {
1563 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "could not open feed");
1564 85f07f22 Fabrice Bellard
            goto send_error;
1565
        }
1566
        c->http_error = 0;
1567
        c->state = HTTPSTATE_RECEIVE_DATA;
1568
        return 0;
1569
    }
1570
1571 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1572 611c5741 Alex Beregszaszi
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1573 cde25790 Philip Gladstone
        http_log("\nGot request:\n%s\n", c->buffer);
1574 3120d2a2 Philip Gladstone
#endif
1575
1576 85f07f22 Fabrice Bellard
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1577 dca21085 Stefano Sabatini
        goto send_status;
1578 85f07f22 Fabrice Bellard
1579
    /* open input stream */
1580
    if (open_input_stream(c, info) < 0) {
1581 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1582 85f07f22 Fabrice Bellard
        goto send_error;
1583
    }
1584
1585
    /* prepare http header */
1586
    q = c->buffer;
1587 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1588 85f07f22 Fabrice Bellard
    mime_type = c->stream->fmt->mime_type;
1589
    if (!mime_type)
1590 087fa475 Alex Beregszaszi
        mime_type = "application/x-octet-stream";
1591 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1592 85f07f22 Fabrice Bellard
1593
    /* for asf, we need extra headers */
1594 8256c0a3 Philip Gladstone
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1595 3120d2a2 Philip Gladstone
        /* Need to allocate a client id */
1596
1597 1df93ae9 Alex Beregszaszi
        c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
1598 3120d2a2 Philip Gladstone
1599 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);
1600 85f07f22 Fabrice Bellard
    }
1601 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1602
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1603 115329f1 Diego Biurrun
1604 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1605
    c->http_error = 0;
1606
    c->buffer_ptr = c->buffer;
1607
    c->buffer_end = q;
1608
    c->state = HTTPSTATE_SEND_HEADER;
1609
    return 0;
1610
 send_error:
1611
    c->http_error = 404;
1612
    q = c->buffer;
1613 a3aa4fed Baptiste Coudurier
    q += snprintf(q, c->buffer_size,
1614
                  "HTTP/1.0 404 Not Found\r\n"
1615
                  "Content-type: text/html\r\n"
1616
                  "\r\n"
1617
                  "<HTML>\n"
1618
                  "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
1619
                  "<BODY>%s</BODY>\n"
1620
                  "</HTML>\n", msg);
1621 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1622
    c->buffer_ptr = c->buffer;
1623
    c->buffer_end = q;
1624
    c->state = HTTPSTATE_SEND_HEADER;
1625
    return 0;
1626 dca21085 Stefano Sabatini
 send_status:
1627
    compute_status(c);
1628 85f07f22 Fabrice Bellard
    c->http_error = 200; /* horrible : we use this value to avoid
1629
                            going to the send data state */
1630
    c->state = HTTPSTATE_SEND_HEADER;
1631
    return 0;
1632
}
1633
1634 0c1a9eda Zdenek Kabelac
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1635 2ac887ba Philip Gladstone
{
1636
    static const char *suffix = " kMGTP";
1637
    const char *s;
1638
1639 611c5741 Alex Beregszaszi
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1640 2ac887ba Philip Gladstone
1641 4733abcb Måns Rullgård
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1642 2ac887ba Philip Gladstone
}
1643
1644 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c)
1645 85f07f22 Fabrice Bellard
{
1646
    HTTPContext *c1;
1647
    FFStream *stream;
1648 2effd274 Fabrice Bellard
    char *p;
1649 85f07f22 Fabrice Bellard
    time_t ti;
1650 2effd274 Fabrice Bellard
    int i, len;
1651 899681cd Björn Axelsson
    ByteIOContext *pb;
1652 cde25790 Philip Gladstone
1653 899681cd Björn Axelsson
    if (url_open_dyn_buf(&pb) < 0) {
1654 2effd274 Fabrice Bellard
        /* XXX: return an error ? */
1655 cde25790 Philip Gladstone
        c->buffer_ptr = c->buffer;
1656 2effd274 Fabrice Bellard
        c->buffer_end = c->buffer;
1657
        return;
1658 cde25790 Philip Gladstone
    }
1659 85f07f22 Fabrice Bellard
1660 2effd274 Fabrice Bellard
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1661
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1662
    url_fprintf(pb, "Pragma: no-cache\r\n");
1663
    url_fprintf(pb, "\r\n");
1664 115329f1 Diego Biurrun
1665 31296f6e Baptiste Coudurier
    url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
1666 0679719d Erik Hovland
    if (c->stream->feed_filename[0])
1667 2effd274 Fabrice Bellard
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1668
    url_fprintf(pb, "</HEAD>\n<BODY>");
1669 17b01199 Stefano Sabatini
    url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
1670 85f07f22 Fabrice Bellard
    /* format status */
1671 2effd274 Fabrice Bellard
    url_fprintf(pb, "<H2>Available Streams</H2>\n");
1672
    url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1673
    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");
1674 85f07f22 Fabrice Bellard
    stream = first_stream;
1675
    while (stream != NULL) {
1676 42a63c6a Philip Gladstone
        char sfilename[1024];
1677
        char *eosf;
1678
1679 a6e14edd Philip Gladstone
        if (stream->feed != stream) {
1680 f7d78f36 Måns Rullgård
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1681 a6e14edd Philip Gladstone
            eosf = sfilename + strlen(sfilename);
1682
            if (eosf - sfilename >= 4) {
1683 611c5741 Alex Beregszaszi
                if (strcmp(eosf - 4, ".asf") == 0)
1684 a6e14edd Philip Gladstone
                    strcpy(eosf - 4, ".asx");
1685 611c5741 Alex Beregszaszi
                else if (strcmp(eosf - 3, ".rm") == 0)
1686 a6e14edd Philip Gladstone
                    strcpy(eosf - 3, ".ram");
1687 25e3e53d Luca Abeni
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1688 829ac53d Fabrice Bellard
                    /* generate a sample RTSP director if
1689
                       unicast. Generate an SDP redirector if
1690
                       multicast */
1691 2effd274 Fabrice Bellard
                    eosf = strrchr(sfilename, '.');
1692
                    if (!eosf)
1693
                        eosf = sfilename + strlen(sfilename);
1694 829ac53d Fabrice Bellard
                    if (stream->is_multicast)
1695
                        strcpy(eosf, ".sdp");
1696
                    else
1697
                        strcpy(eosf, ".rtsp");
1698 a6e14edd Philip Gladstone
                }
1699 42a63c6a Philip Gladstone
            }
1700 115329f1 Diego Biurrun
1701
            url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1702 a6e14edd Philip Gladstone
                         sfilename, stream->filename);
1703 2effd274 Fabrice Bellard
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1704 2ac887ba Philip Gladstone
                        stream->conns_served);
1705 2effd274 Fabrice Bellard
            fmt_bytecount(pb, stream->bytes_served);
1706 a6e14edd Philip Gladstone
            switch(stream->stream_type) {
1707 ace21da3 Baptiste Coudurier
            case STREAM_TYPE_LIVE: {
1708 a6e14edd Philip Gladstone
                    int audio_bit_rate = 0;
1709
                    int video_bit_rate = 0;
1710 58445440 Zdenek Kabelac
                    const char *audio_codec_name = "";
1711
                    const char *video_codec_name = "";
1712
                    const char *audio_codec_name_extra = "";
1713
                    const char *video_codec_name_extra = "";
1714 a6e14edd Philip Gladstone
1715
                    for(i=0;i<stream->nb_streams;i++) {
1716
                        AVStream *st = stream->streams[i];
1717 01f4895c Michael Niedermayer
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1718
                        switch(st->codec->codec_type) {
1719 a6e14edd Philip Gladstone
                        case CODEC_TYPE_AUDIO:
1720 01f4895c Michael Niedermayer
                            audio_bit_rate += st->codec->bit_rate;
1721 a6e14edd Philip Gladstone
                            if (codec) {
1722
                                if (*audio_codec_name)
1723
                                    audio_codec_name_extra = "...";
1724
                                audio_codec_name = codec->name;
1725
                            }
1726
                            break;
1727
                        case CODEC_TYPE_VIDEO:
1728 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1729 a6e14edd Philip Gladstone
                            if (codec) {
1730
                                if (*video_codec_name)
1731
                                    video_codec_name_extra = "...";
1732
                                video_codec_name = codec->name;
1733
                            }
1734
                            break;
1735 e240a0bb Fabrice Bellard
                        case CODEC_TYPE_DATA:
1736 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1737 e240a0bb Fabrice Bellard
                            break;
1738 a6e14edd Philip Gladstone
                        default:
1739 0f4e8165 Ronald S. Bultje
                            abort();
1740 79c4ea3c Philip Gladstone
                        }
1741 85f07f22 Fabrice Bellard
                    }
1742 115329f1 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",
1743 a6e14edd Philip Gladstone
                                 stream->fmt->name,
1744 6edd6884 Fabrice Bellard
                                 stream->bandwidth,
1745 a6e14edd Philip Gladstone
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1746
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1747 611c5741 Alex Beregszaszi
                    if (stream->feed)
1748 2effd274 Fabrice Bellard
                        url_fprintf(pb, "<TD>%s", stream->feed->filename);
1749 611c5741 Alex Beregszaszi
                    else
1750 2effd274 Fabrice Bellard
                        url_fprintf(pb, "<TD>%s", stream->feed_filename);
1751
                    url_fprintf(pb, "\n");
1752 85f07f22 Fabrice Bellard
                }
1753 a6e14edd Philip Gladstone
                break;
1754
            default:
1755 2effd274 Fabrice Bellard
                url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1756 a6e14edd Philip Gladstone
                break;
1757 85f07f22 Fabrice Bellard
            }
1758
        }
1759
        stream = stream->next;
1760
    }
1761 2effd274 Fabrice Bellard
    url_fprintf(pb, "</TABLE>\n");
1762 a6e14edd Philip Gladstone
1763
    stream = first_stream;
1764
    while (stream != NULL) {
1765
        if (stream->feed == stream) {
1766 2effd274 Fabrice Bellard
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1767 cde25790 Philip Gladstone
            if (stream->pid) {
1768 2effd274 Fabrice Bellard
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1769 cde25790 Philip Gladstone
1770 2effd274 Fabrice Bellard
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1771
                {
1772
                    FILE *pid_stat;
1773
                    char ps_cmd[64];
1774
1775
                    /* This is somewhat linux specific I guess */
1776 115329f1 Diego Biurrun
                    snprintf(ps_cmd, sizeof(ps_cmd),
1777
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1778 2effd274 Fabrice Bellard
                             stream->pid);
1779 115329f1 Diego Biurrun
1780 2effd274 Fabrice Bellard
                    pid_stat = popen(ps_cmd, "r");
1781
                    if (pid_stat) {
1782
                        char cpuperc[10];
1783
                        char cpuused[64];
1784 115329f1 Diego Biurrun
1785
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1786 2effd274 Fabrice Bellard
                                   cpuused) == 2) {
1787
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1788
                                         cpuperc, cpuused);
1789
                        }
1790
                        fclose(pid_stat);
1791 cde25790 Philip Gladstone
                    }
1792
                }
1793
#endif
1794
1795 2effd274 Fabrice Bellard
                url_fprintf(pb, "<p>");
1796 cde25790 Philip Gladstone
            }
1797 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");
1798 a6e14edd Philip Gladstone
1799
            for (i = 0; i < stream->nb_streams; i++) {
1800
                AVStream *st = stream->streams[i];
1801 01f4895c Michael Niedermayer
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1802 b29f97d1 Zdenek Kabelac
                const char *type = "unknown";
1803 b582f314 Philip Gladstone
                char parameters[64];
1804
1805
                parameters[0] = 0;
1806 a6e14edd Philip Gladstone
1807 01f4895c Michael Niedermayer
                switch(st->codec->codec_type) {
1808 a6e14edd Philip Gladstone
                case CODEC_TYPE_AUDIO:
1809
                    type = "audio";
1810 acdc8520 Alex Beregszaszi
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1811 a6e14edd Philip Gladstone
                    break;
1812
                case CODEC_TYPE_VIDEO:
1813
                    type = "video";
1814 01f4895c Michael Niedermayer
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1815
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1816 a6e14edd Philip Gladstone
                    break;
1817
                default:
1818 0f4e8165 Ronald S. Bultje
                    abort();
1819 a6e14edd Philip Gladstone
                }
1820 2effd274 Fabrice Bellard
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1821 01f4895c Michael Niedermayer
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1822 a6e14edd Philip Gladstone
            }
1823 2effd274 Fabrice Bellard
            url_fprintf(pb, "</table>\n");
1824 a6e14edd Philip Gladstone
1825 115329f1 Diego Biurrun
        }
1826 a6e14edd Philip Gladstone
        stream = stream->next;
1827
    }
1828 115329f1 Diego Biurrun
1829 85f07f22 Fabrice Bellard
#if 0
1830
    {
1831
        float avg;
1832
        AVCodecContext *enc;
1833
        char buf[1024];
1834 115329f1 Diego Biurrun

1835 85f07f22 Fabrice Bellard
        /* feed status */
1836
        stream = first_feed;
1837
        while (stream != NULL) {
1838 2effd274 Fabrice Bellard
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1839
            url_fprintf(pb, "<TABLE>\n");
1840
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1841 85f07f22 Fabrice Bellard
            for(i=0;i<stream->nb_streams;i++) {
1842
                AVStream *st = stream->streams[i];
1843
                FeedData *fdata = st->priv_data;
1844 01f4895c Michael Niedermayer
                enc = st->codec;
1845 115329f1 Diego Biurrun

1846 85f07f22 Fabrice Bellard
                avcodec_string(buf, sizeof(buf), enc);
1847
                avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1848
                if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1849
                    avg /= enc->frame_size;
1850 949b1a13 Steve L'Homme
                url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
1851 85f07f22 Fabrice Bellard
                             buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1852
            }
1853 2effd274 Fabrice Bellard
            url_fprintf(pb, "</TABLE>\n");
1854 85f07f22 Fabrice Bellard
            stream = stream->next_feed;
1855
        }
1856
    }
1857
#endif
1858
1859
    /* connection status */
1860 2effd274 Fabrice Bellard
    url_fprintf(pb, "<H2>Connection Status</H2>\n");
1861 85f07f22 Fabrice Bellard
1862 2effd274 Fabrice Bellard
    url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1863 85f07f22 Fabrice Bellard
                 nb_connections, nb_max_connections);
1864
1865 0be4b8d9 Baptiste Coudurier
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<BR>\n",
1866 6edd6884 Fabrice Bellard
                 current_bandwidth, max_bandwidth);
1867 42a63c6a Philip Gladstone
1868 2effd274 Fabrice Bellard
    url_fprintf(pb, "<TABLE>\n");
1869
    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");
1870 85f07f22 Fabrice Bellard
    c1 = first_http_ctx;
1871
    i = 0;
1872 2effd274 Fabrice Bellard
    while (c1 != NULL) {
1873 cde25790 Philip Gladstone
        int bitrate;
1874
        int j;
1875
1876
        bitrate = 0;
1877 2effd274 Fabrice Bellard
        if (c1->stream) {
1878
            for (j = 0; j < c1->stream->nb_streams; j++) {
1879 2d563d2f Alex Beregszaszi
                if (!c1->stream->feed)
1880 01f4895c Michael Niedermayer
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1881 2d563d2f Alex Beregszaszi
                else if (c1->feed_streams[j] >= 0)
1882
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1883 cde25790 Philip Gladstone
            }
1884
        }
1885
1886 85f07f22 Fabrice Bellard
        i++;
1887
        p = inet_ntoa(c1->from_addr.sin_addr);
1888 115329f1 Diego Biurrun
        url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1889
                    i,
1890
                    c1->stream ? c1->stream->filename : "",
1891 2effd274 Fabrice Bellard
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1892 115329f1 Diego Biurrun
                    p,
1893 2effd274 Fabrice Bellard
                    c1->protocol,
1894
                    http_state[c1->state]);
1895
        fmt_bytecount(pb, bitrate);
1896
        url_fprintf(pb, "<td align=right>");
1897
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1898
        url_fprintf(pb, "<td align=right>");
1899
        fmt_bytecount(pb, c1->data_count);
1900
        url_fprintf(pb, "\n");
1901 85f07f22 Fabrice Bellard
        c1 = c1->next;
1902
    }
1903 2effd274 Fabrice Bellard
    url_fprintf(pb, "</TABLE>\n");
1904 115329f1 Diego Biurrun
1905 85f07f22 Fabrice Bellard
    /* date */
1906
    ti = time(NULL);
1907
    p = ctime(&ti);
1908 2effd274 Fabrice Bellard
    url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1909
    url_fprintf(pb, "</BODY>\n</HTML>\n");
1910 85f07f22 Fabrice Bellard
1911 2effd274 Fabrice Bellard
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1912
    c->buffer_ptr = c->pb_buffer;
1913
    c->buffer_end = c->pb_buffer + len;
1914 85f07f22 Fabrice Bellard
}
1915
1916 2effd274 Fabrice Bellard
/* check if the parser needs to be opened for stream i */
1917
static void open_parser(AVFormatContext *s, int i)
1918 85f07f22 Fabrice Bellard
{
1919 2effd274 Fabrice Bellard
    AVStream *st = s->streams[i];
1920
    AVCodec *codec;
1921 31def229 Philip Gladstone
1922 01f4895c Michael Niedermayer
    if (!st->codec->codec) {
1923
        codec = avcodec_find_decoder(st->codec->codec_id);
1924 2effd274 Fabrice Bellard
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1925 01f4895c Michael Niedermayer
            st->codec->parse_only = 1;
1926 611c5741 Alex Beregszaszi
            if (avcodec_open(st->codec, codec) < 0)
1927 01f4895c Michael Niedermayer
                st->codec->parse_only = 0;
1928 cde25790 Philip Gladstone
        }
1929
    }
1930 85f07f22 Fabrice Bellard
}
1931
1932
static int open_input_stream(HTTPContext *c, const char *info)
1933
{
1934
    char buf[128];
1935
    char input_filename[1024];
1936
    AVFormatContext *s;
1937 c351cc7f Baptiste Coudurier
    int buf_size, i, ret;
1938 0c1a9eda Zdenek Kabelac
    int64_t stream_pos;
1939 85f07f22 Fabrice Bellard
1940
    /* find file name */
1941
    if (c->stream->feed) {
1942
        strcpy(input_filename, c->stream->feed->feed_filename);
1943
        buf_size = FFM_PACKET_SIZE;
1944
        /* compute position (absolute time) */
1945 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1946 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 0);
1947 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1948
                return -1;
1949 ace21da3 Baptiste Coudurier
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1950 f747e6d3 Philip Gladstone
            int prebuffer = strtol(buf, 0, 10);
1951 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1952 611c5741 Alex Beregszaszi
        } else
1953 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1954 85f07f22 Fabrice Bellard
    } else {
1955
        strcpy(input_filename, c->stream->feed_filename);
1956
        buf_size = 0;
1957
        /* compute position (relative time) */
1958 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1959 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 1);
1960 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1961
                return -1;
1962 ace21da3 Baptiste Coudurier
        } else
1963 85f07f22 Fabrice Bellard
            stream_pos = 0;
1964
    }
1965
    if (input_filename[0] == '\0')
1966
        return -1;
1967
1968 8256c0a3 Philip Gladstone
#if 0
1969
    { time_t when = stream_pos / 1000000;
1970 949b1a13 Steve L'Homme
    http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
1971 8256c0a3 Philip Gladstone
    }
1972
#endif
1973
1974 85f07f22 Fabrice Bellard
    /* open stream */
1975 c351cc7f Baptiste Coudurier
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1976
                                  buf_size, c->stream->ap_in)) < 0) {
1977
        http_log("could not open %s: %d\n", input_filename, ret);
1978 85f07f22 Fabrice Bellard
        return -1;
1979 2effd274 Fabrice Bellard
    }
1980 9dc0bc3d Luca Abeni
    s->flags |= AVFMT_FLAG_GENPTS;
1981 85f07f22 Fabrice Bellard
    c->fmt_in = s;
1982 89da5781 Luca Abeni
    av_find_stream_info(c->fmt_in);
1983 115329f1 Diego Biurrun
1984 2effd274 Fabrice Bellard
    /* open each parser */
1985
    for(i=0;i<s->nb_streams;i++)
1986
        open_parser(s, i);
1987
1988
    /* choose stream as clock source (we favorize video stream if
1989
       present) for packet sending */
1990
    c->pts_stream_index = 0;
1991
    for(i=0;i<c->stream->nb_streams;i++) {
1992 115329f1 Diego Biurrun
        if (c->pts_stream_index == 0 &&
1993 01f4895c Michael Niedermayer
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
1994 2effd274 Fabrice Bellard
            c->pts_stream_index = i;
1995
        }
1996
    }
1997 85f07f22 Fabrice Bellard
1998 e8d27bc3 Philip Gladstone
#if 1
1999 611c5741 Alex Beregszaszi
    if (c->fmt_in->iformat->read_seek)
2000 60a04f7f Baptiste Coudurier
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2001 e240a0bb Fabrice Bellard
#endif
2002 2effd274 Fabrice Bellard
    /* set the start time (needed for maxtime and RTP packet timing) */
2003
    c->start_time = cur_time;
2004
    c->first_pts = AV_NOPTS_VALUE;
2005 85f07f22 Fabrice Bellard
    return 0;
2006
}
2007
2008 e240a0bb Fabrice Bellard
/* return the server clock (in us) */
2009
static int64_t get_server_clock(HTTPContext *c)
2010 2effd274 Fabrice Bellard
{
2011 e240a0bb Fabrice Bellard
    /* compute current pts value from system time */
2012 c3f58185 Alex Beregszaszi
    return (cur_time - c->start_time) * 1000;
2013 2effd274 Fabrice Bellard
}
2014
2015 e240a0bb Fabrice Bellard
/* return the estimated time at which the current packet must be sent
2016
   (in us) */
2017
static int64_t get_packet_send_clock(HTTPContext *c)
2018 2effd274 Fabrice Bellard
{
2019 e240a0bb Fabrice Bellard
    int bytes_left, bytes_sent, frame_bytes;
2020 115329f1 Diego Biurrun
2021 e240a0bb Fabrice Bellard
    frame_bytes = c->cur_frame_bytes;
2022 611c5741 Alex Beregszaszi
    if (frame_bytes <= 0)
2023 e240a0bb Fabrice Bellard
        return c->cur_pts;
2024 611c5741 Alex Beregszaszi
    else {
2025 e240a0bb Fabrice Bellard
        bytes_left = c->buffer_end - c->buffer_ptr;
2026
        bytes_sent = frame_bytes - bytes_left;
2027
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2028 2effd274 Fabrice Bellard
    }
2029
}
2030
2031
2032
static int http_prepare_data(HTTPContext *c)
2033
{
2034
    int i, len, ret;
2035
    AVFormatContext *ctx;
2036
2037 bc351386 Fabrice Bellard
    av_freep(&c->pb_buffer);
2038 2effd274 Fabrice Bellard
    switch(c->state) {
2039
    case HTTPSTATE_SEND_DATA_HEADER:
2040
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2041 f7d78f36 Måns Rullgård
        av_strlcpy(c->fmt_ctx.author, c->stream->author,
2042
                   sizeof(c->fmt_ctx.author));
2043
        av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2044
                   sizeof(c->fmt_ctx.comment));
2045
        av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2046
                   sizeof(c->fmt_ctx.copyright));
2047
        av_strlcpy(c->fmt_ctx.title, c->stream->title,
2048
                   sizeof(c->fmt_ctx.title));
2049 2effd274 Fabrice Bellard
2050 3d9cc27d Baptiste Coudurier
        for(i=0;i<c->stream->nb_streams;i++) {
2051 2effd274 Fabrice Bellard
            AVStream *st;
2052 bb270c08 Diego Biurrun
            AVStream *src;
2053 2effd274 Fabrice Bellard
            st = av_mallocz(sizeof(AVStream));
2054
            c->fmt_ctx.streams[i] = st;
2055
            /* if file or feed, then just take streams from FFStream struct */
2056 115329f1 Diego Biurrun
            if (!c->stream->feed ||
2057 2effd274 Fabrice Bellard
                c->stream->feed == c->stream)
2058 7c054ea7 Philip Gladstone
                src = c->stream->streams[i];
2059 2effd274 Fabrice Bellard
            else
2060 7c054ea7 Philip Gladstone
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2061
2062 bb270c08 Diego Biurrun
            *st = *src;
2063
            st->priv_data = 0;
2064 01f4895c Michael Niedermayer
            st->codec->frame_number = 0; /* XXX: should be done in
2065 2effd274 Fabrice Bellard
                                           AVStream, not in codec */
2066
        }
2067 3d9cc27d Baptiste Coudurier
        /* set output format parameters */
2068
        c->fmt_ctx.oformat = c->stream->fmt;
2069
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2070
2071 2effd274 Fabrice Bellard
        c->got_key_frame = 0;
2072
2073
        /* prepare header and save header data in a stream */
2074
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2075
            /* XXX: potential leak */
2076
            return -1;
2077
        }
2078 899681cd Björn Axelsson
        c->fmt_ctx.pb->is_streamed = 1;
2079 2effd274 Fabrice Bellard
2080 8aae202e Baptiste Coudurier
        /*
2081
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2082
         * Default value from FFmpeg
2083
         * Try to set it use configuration option
2084
         */
2085
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2086
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2087
2088 3c27199b Fabrice Bellard
        av_set_parameters(&c->fmt_ctx, NULL);
2089 929a9b75 Baptiste Coudurier
        if (av_write_header(&c->fmt_ctx) < 0) {
2090
            http_log("Error writing output header\n");
2091 f75cdda7 Alex Beregszaszi
            return -1;
2092 929a9b75 Baptiste Coudurier
        }
2093 2effd274 Fabrice Bellard
2094 899681cd Björn Axelsson
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2095 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2096
        c->buffer_end = c->pb_buffer + len;
2097
2098
        c->state = HTTPSTATE_SEND_DATA;
2099 85f07f22 Fabrice Bellard
        c->last_packet_sent = 0;
2100
        break;
2101
    case HTTPSTATE_SEND_DATA:
2102
        /* find a new packet */
2103 3b371676 Baptiste Coudurier
        /* read a packet from the input stream */
2104
        if (c->stream->feed)
2105
            ffm_set_write_index(c->fmt_in,
2106
                                c->stream->feed->feed_write_index,
2107
                                c->stream->feed->feed_size);
2108
2109
        if (c->stream->max_time &&
2110
            c->stream->max_time + c->start_time - cur_time < 0)
2111
            /* We have timed out */
2112
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2113
        else {
2114
            AVPacket pkt;
2115
        redo:
2116
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2117
                if (c->stream->feed && c->stream->feed->feed_opened) {
2118
                    /* if coming from feed, it means we reached the end of the
2119
                       ffm file, so must wait for more data */
2120
                    c->state = HTTPSTATE_WAIT_FEED;
2121
                    return 1; /* state changed */
2122 2effd274 Fabrice Bellard
                } else {
2123 3b371676 Baptiste Coudurier
                    if (c->stream->loop) {
2124
                        av_close_input_file(c->fmt_in);
2125
                        c->fmt_in = NULL;
2126
                        if (open_input_stream(c, "") < 0)
2127
                            goto no_loop;
2128
                        goto redo;
2129
                    } else {
2130
                    no_loop:
2131
                        /* must send trailer now because eof or error */
2132
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2133 1bc1cfdd Giancarlo Formicuccia
                    }
2134 3b371676 Baptiste Coudurier
                }
2135
            } else {
2136 084a8912 Baptiste Coudurier
                int source_index = pkt.stream_index;
2137 3b371676 Baptiste Coudurier
                /* update first pts if needed */
2138
                if (c->first_pts == AV_NOPTS_VALUE) {
2139
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2140
                    c->start_time = cur_time;
2141
                }
2142
                /* send it to the appropriate stream */
2143
                if (c->stream->feed) {
2144
                    /* if coming from a feed, select the right stream */
2145
                    if (c->switch_pending) {
2146
                        c->switch_pending = 0;
2147 cde25790 Philip Gladstone
                        for(i=0;i<c->stream->nb_streams;i++) {
2148 3b371676 Baptiste Coudurier
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2149 611c5741 Alex Beregszaszi
                                if (pkt.flags & PKT_FLAG_KEY)
2150 3b371676 Baptiste Coudurier
                                    do_switch_stream(c, i);
2151
                            if (c->switch_feed_streams[i] >= 0)
2152
                                c->switch_pending = 1;
2153 cde25790 Philip Gladstone
                        }
2154 3b371676 Baptiste Coudurier
                    }
2155
                    for(i=0;i<c->stream->nb_streams;i++) {
2156
                        if (c->feed_streams[i] == pkt.stream_index) {
2157 78728064 Baptiste Coudurier
                            AVStream *st = c->fmt_in->streams[source_index];
2158 3b371676 Baptiste Coudurier
                            pkt.stream_index = i;
2159 180b7026 Baptiste Coudurier
                            if (pkt.flags & PKT_FLAG_KEY &&
2160
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2161
                                 c->stream->nb_streams == 1))
2162 0332f549 Baptiste Coudurier
                                c->got_key_frame = 1;
2163
                            if (!c->stream->send_on_key || c->got_key_frame)
2164 3b371676 Baptiste Coudurier
                                goto send_it;
2165
                        }
2166
                    }
2167
                } else {
2168
                    AVCodecContext *codec;
2169 dc3a6a36 Baptiste Coudurier
                    AVStream *ist, *ost;
2170
                send_it:
2171
                    ist = c->fmt_in->streams[source_index];
2172 3b371676 Baptiste Coudurier
                    /* specific handling for RTP: we use several
2173
                       output stream (one for each RTP
2174
                       connection). XXX: need more abstract handling */
2175
                    if (c->is_packetized) {
2176
                        /* compute send time and duration */
2177 8f56ccca Baptiste Coudurier
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2178
                        if (ist->start_time != AV_NOPTS_VALUE)
2179
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2180
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2181 e240a0bb Fabrice Bellard
#if 0
2182 3b371676 Baptiste Coudurier
                        printf("index=%d pts=%0.3f duration=%0.6f\n",
2183
                               pkt.stream_index,
2184
                               (double)c->cur_pts /
2185
                               AV_TIME_BASE,
2186
                               (double)c->cur_frame_duration /
2187
                               AV_TIME_BASE);
2188 e240a0bb Fabrice Bellard
#endif
2189 3b371676 Baptiste Coudurier
                        /* find RTP context */
2190
                        c->packet_stream_index = pkt.stream_index;
2191
                        ctx = c->rtp_ctx[c->packet_stream_index];
2192
                        if(!ctx) {
2193 8a0b55ff Baptiste Coudurier
                            av_free_packet(&pkt);
2194 3b371676 Baptiste Coudurier
                            break;
2195 8a0b55ff Baptiste Coudurier
                        }
2196 3b371676 Baptiste Coudurier
                        codec = ctx->streams[0]->codec;
2197
                        /* only one stream per RTP connection */
2198
                        pkt.stream_index = 0;
2199
                    } else {
2200
                        ctx = &c->fmt_ctx;
2201
                        /* Fudge here */
2202 3ab29d8e Baptiste Coudurier
                        codec = ctx->streams[pkt.stream_index]->codec;
2203 3b371676 Baptiste Coudurier
                    }
2204
2205
                    if (c->is_packetized) {
2206
                        int max_packet_size;
2207 90abbdba Ronald S. Bultje
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2208 3b371676 Baptiste Coudurier
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2209
                        else
2210
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2211
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2212
                    } else {
2213
                        ret = url_open_dyn_buf(&ctx->pb);
2214
                    }
2215
                    if (ret < 0) {
2216
                        /* XXX: potential leak */
2217
                        return -1;
2218
                    }
2219 3ab29d8e Baptiste Coudurier
                    ost = ctx->streams[pkt.stream_index];
2220
2221 b0675954 Baptiste Coudurier
                    ctx->pb->is_streamed = 1;
2222 3b371676 Baptiste Coudurier
                    if (pkt.dts != AV_NOPTS_VALUE)
2223 d80904cc Baptiste Coudurier
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2224 3b371676 Baptiste Coudurier
                    if (pkt.pts != AV_NOPTS_VALUE)
2225 d80904cc Baptiste Coudurier
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2226
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2227 3766ed72 Baptiste Coudurier
                    if (av_write_frame(ctx, &pkt) < 0) {
2228
                        http_log("Error writing frame to output\n");
2229 3b371676 Baptiste Coudurier
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2230 3766ed72 Baptiste Coudurier
                    }
2231 3b371676 Baptiste Coudurier
2232
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2233
                    c->cur_frame_bytes = len;
2234
                    c->buffer_ptr = c->pb_buffer;
2235
                    c->buffer_end = c->pb_buffer + len;
2236
2237
                    codec->frame_number++;
2238
                    if (len == 0) {
2239
                        av_free_packet(&pkt);
2240
                        goto redo;
2241 f747e6d3 Philip Gladstone
                    }
2242 85f07f22 Fabrice Bellard
                }
2243 3b371676 Baptiste Coudurier
                av_free_packet(&pkt);
2244 85f07f22 Fabrice Bellard
            }
2245 3b371676 Baptiste Coudurier
        }
2246 85f07f22 Fabrice Bellard
        break;
2247
    default:
2248
    case HTTPSTATE_SEND_DATA_TRAILER:
2249
        /* last packet test ? */
2250 2effd274 Fabrice Bellard
        if (c->last_packet_sent || c->is_packetized)
2251 85f07f22 Fabrice Bellard
            return -1;
2252 2effd274 Fabrice Bellard
        ctx = &c->fmt_ctx;
2253 85f07f22 Fabrice Bellard
        /* prepare header */
2254 2effd274 Fabrice Bellard
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2255
            /* XXX: potential leak */
2256
            return -1;
2257
        }
2258 58bd615f Baptiste Coudurier
        c->fmt_ctx.pb->is_streamed = 1;
2259 2effd274 Fabrice Bellard
        av_write_trailer(ctx);
2260 899681cd Björn Axelsson
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2261 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2262
        c->buffer_end = c->pb_buffer + len;
2263
2264 85f07f22 Fabrice Bellard
        c->last_packet_sent = 1;
2265
        break;
2266
    }
2267
    return 0;
2268
}
2269
2270
/* should convert the format at the same time */
2271 bc351386 Fabrice Bellard
/* send data starting at c->buffer_ptr to the output connection
2272
   (either UDP or TCP connection) */
2273 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c)
2274 85f07f22 Fabrice Bellard
{
2275 e240a0bb Fabrice Bellard
    int len, ret;
2276 85f07f22 Fabrice Bellard
2277 bc351386 Fabrice Bellard
    for(;;) {
2278
        if (c->buffer_ptr >= c->buffer_end) {
2279
            ret = http_prepare_data(c);
2280
            if (ret < 0)
2281
                return -1;
2282 611c5741 Alex Beregszaszi
            else if (ret != 0)
2283 bc351386 Fabrice Bellard
                /* state change requested */
2284
                break;
2285 2effd274 Fabrice Bellard
        } else {
2286 bc351386 Fabrice Bellard
            if (c->is_packetized) {
2287
                /* RTP data output */
2288
                len = c->buffer_end - c->buffer_ptr;
2289
                if (len < 4) {
2290
                    /* fail safe - should never happen */
2291
                fail1:
2292
                    c->buffer_ptr = c->buffer_end;
2293 2effd274 Fabrice Bellard
                    return 0;
2294
                }
2295 bc351386 Fabrice Bellard
                len = (c->buffer_ptr[0] << 24) |
2296
                    (c->buffer_ptr[1] << 16) |
2297
                    (c->buffer_ptr[2] << 8) |
2298
                    (c->buffer_ptr[3]);
2299
                if (len > (c->buffer_end - c->buffer_ptr))
2300
                    goto fail1;
2301 e240a0bb Fabrice Bellard
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2302
                    /* nothing to send yet: we can wait */
2303
                    return 0;
2304
                }
2305
2306
                c->data_count += len;
2307
                update_datarate(&c->datarate, c->data_count);
2308
                if (c->stream)
2309
                    c->stream->bytes_served += len;
2310
2311 90abbdba Ronald S. Bultje
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2312 bc351386 Fabrice Bellard
                    /* RTP packets are sent inside the RTSP TCP connection */
2313 899681cd Björn Axelsson
                    ByteIOContext *pb;
2314 bc351386 Fabrice Bellard
                    int interleaved_index, size;
2315
                    uint8_t header[4];
2316
                    HTTPContext *rtsp_c;
2317 115329f1 Diego Biurrun
2318 bc351386 Fabrice Bellard
                    rtsp_c = c->rtsp_c;
2319
                    /* if no RTSP connection left, error */
2320
                    if (!rtsp_c)
2321
                        return -1;
2322
                    /* if already sending something, then wait. */
2323 611c5741 Alex Beregszaszi
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2324 bc351386 Fabrice Bellard
                        break;
2325 899681cd Björn Axelsson
                    if (url_open_dyn_buf(&pb) < 0)
2326 bc351386 Fabrice Bellard
                        goto fail1;
2327
                    interleaved_index = c->packet_stream_index * 2;
2328
                    /* RTCP packets are sent at odd indexes */
2329
                    if (c->buffer_ptr[1] == 200)
2330
                        interleaved_index++;
2331
                    /* write RTSP TCP header */
2332
                    header[0] = '$';
2333
                    header[1] = interleaved_index;
2334
                    header[2] = len >> 8;
2335
                    header[3] = len;
2336
                    put_buffer(pb, header, 4);
2337
                    /* write RTP packet data */
2338
                    c->buffer_ptr += 4;
2339
                    put_buffer(pb, c->buffer_ptr, len);
2340
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2341
                    /* prepare asynchronous TCP sending */
2342
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2343
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2344 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2345 115329f1 Diego Biurrun
2346 e240a0bb Fabrice Bellard
                    /* send everything we can NOW */
2347 c60202df Alex Beregszaszi
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2348
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2349 611c5741 Alex Beregszaszi
                    if (len > 0)
2350 e240a0bb Fabrice Bellard
                        rtsp_c->packet_buffer_ptr += len;
2351
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2352
                        /* if we could not send all the data, we will
2353
                           send it later, so a new state is needed to
2354
                           "lock" the RTSP TCP connection */
2355
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2356
                        break;
2357 611c5741 Alex Beregszaszi
                    } else
2358 e240a0bb Fabrice Bellard
                        /* all data has been sent */
2359
                        av_freep(&c->packet_buffer);
2360
                } else {
2361
                    /* send RTP packet directly in UDP */
2362 bc351386 Fabrice Bellard
                    c->buffer_ptr += 4;
2363 115329f1 Diego Biurrun
                    url_write(c->rtp_handles[c->packet_stream_index],
2364 bc351386 Fabrice Bellard
                              c->buffer_ptr, len);
2365 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2366
                    /* here we continue as we can send several packets per 10 ms slot */
2367 bc351386 Fabrice Bellard
                }
2368
            } else {
2369
                /* TCP data output */
2370 c60202df Alex Beregszaszi
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2371 bc351386 Fabrice Bellard
                if (len < 0) {
2372 8da4034f Alex Beregszaszi
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2373 611c5741 Alex Beregszaszi
                        ff_neterrno() != FF_NETERROR(EINTR))
2374 bc351386 Fabrice Bellard
                        /* error : close connection */
2375
                        return -1;
2376 611c5741 Alex Beregszaszi
                    else
2377 bc351386 Fabrice Bellard
                        return 0;
2378 611c5741 Alex Beregszaszi
                } else
2379 bc351386 Fabrice Bellard
                    c->buffer_ptr += len;
2380 611c5741 Alex Beregszaszi
2381 e240a0bb Fabrice Bellard
                c->data_count += len;
2382
                update_datarate(&c->datarate, c->data_count);
2383
                if (c->stream)
2384
                    c->stream->bytes_served += len;
2385
                break;
2386 2effd274 Fabrice Bellard
            }
2387 85f07f22 Fabrice Bellard
        }
2388 bc351386 Fabrice Bellard
    } /* for(;;) */
2389 85f07f22 Fabrice Bellard
    return 0;
2390
}
2391
2392
static int http_start_receive_data(HTTPContext *c)
2393
{
2394
    int fd;
2395
2396
    if (c->stream->feed_opened)
2397
        return -1;
2398
2399 e322ea48 Philip Gladstone
    /* Don't permit writing to this one */
2400
    if (c->stream->readonly)
2401
        return -1;
2402
2403 85f07f22 Fabrice Bellard
    /* open feed */
2404
    fd = open(c->stream->feed_filename, O_RDWR);
2405 929a9b75 Baptiste Coudurier
    if (fd < 0) {
2406
        http_log("Error opening feeder file: %s\n", strerror(errno));
2407 85f07f22 Fabrice Bellard
        return -1;
2408 929a9b75 Baptiste Coudurier
    }
2409 85f07f22 Fabrice Bellard
    c->feed_fd = fd;
2410 115329f1 Diego Biurrun
2411 85f07f22 Fabrice Bellard
    c->stream->feed_write_index = ffm_read_write_index(fd);
2412
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2413
    lseek(fd, 0, SEEK_SET);
2414
2415
    /* init buffer input */
2416
    c->buffer_ptr = c->buffer;
2417
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2418
    c->stream->feed_opened = 1;
2419
    return 0;
2420
}
2421 115329f1 Diego Biurrun
2422 85f07f22 Fabrice Bellard
static int http_receive_data(HTTPContext *c)
2423
{
2424
    HTTPContext *c1;
2425
2426 a6e14edd Philip Gladstone
    if (c->buffer_end > c->buffer_ptr) {
2427
        int len;
2428
2429 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2430 a6e14edd Philip Gladstone
        if (len < 0) {
2431 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2432 611c5741 Alex Beregszaszi
                ff_neterrno() != FF_NETERROR(EINTR))
2433 a6e14edd Philip Gladstone
                /* error : close connection */
2434
                goto fail;
2435 611c5741 Alex Beregszaszi
        } else if (len == 0)
2436 a6e14edd Philip Gladstone
            /* end of connection : close it */
2437
            goto fail;
2438 611c5741 Alex Beregszaszi
        else {
2439 a6e14edd Philip Gladstone
            c->buffer_ptr += len;
2440
            c->data_count += len;
2441 5eb765ef Philip Gladstone
            update_datarate(&c->datarate, c->data_count);
2442 a6e14edd Philip Gladstone
        }
2443
    }
2444
2445 d445a7e9 Philip Gladstone
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2446
        if (c->buffer[0] != 'f' ||
2447
            c->buffer[1] != 'm') {
2448
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2449
            goto fail;
2450
        }
2451
    }
2452
2453 85f07f22 Fabrice Bellard
    if (c->buffer_ptr >= c->buffer_end) {
2454 f747e6d3 Philip Gladstone
        FFStream *feed = c->stream;
2455 85f07f22 Fabrice Bellard
        /* a packet has been received : write it in the store, except
2456
           if header */
2457
        if (c->data_count > FFM_PACKET_SIZE) {
2458 115329f1 Diego Biurrun
2459 949b1a13 Steve L'Homme
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2460 85f07f22 Fabrice Bellard
            /* XXX: use llseek or url_seek */
2461
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2462 929a9b75 Baptiste Coudurier
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2463
                http_log("Error writing to feed file: %s\n", strerror(errno));
2464
                goto fail;
2465
            }
2466 115329f1 Diego Biurrun
2467 85f07f22 Fabrice Bellard
            feed->feed_write_index += FFM_PACKET_SIZE;
2468
            /* update file size */
2469
            if (feed->feed_write_index > c->stream->feed_size)
2470
                feed->feed_size = feed->feed_write_index;
2471
2472
            /* handle wrap around if max file size reached */
2473 6b0bdc75 Alex Beregszaszi
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2474 85f07f22 Fabrice Bellard
                feed->feed_write_index = FFM_PACKET_SIZE;
2475
2476
            /* write index */
2477
            ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2478
2479
            /* wake up any waiting connections */
2480
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2481 115329f1 Diego Biurrun
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2482 611c5741 Alex Beregszaszi
                    c1->stream->feed == c->stream->feed)
2483 85f07f22 Fabrice Bellard
                    c1->state = HTTPSTATE_SEND_DATA;
2484
            }
2485 f747e6d3 Philip Gladstone
        } else {
2486
            /* We have a header in our hands that contains useful data */
2487 f2972c8c Baptiste Coudurier
            AVFormatContext *s = NULL;
2488
            ByteIOContext *pb;
2489 bd7cf6ad Fabrice Bellard
            AVInputFormat *fmt_in;
2490 f747e6d3 Philip Gladstone
            int i;
2491
2492 bd7cf6ad Fabrice Bellard
            /* use feed output format name to find corresponding input format */
2493
            fmt_in = av_find_input_format(feed->fmt->name);
2494
            if (!fmt_in)
2495
                goto fail;
2496
2497 697efa36 Baptiste Coudurier
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2498
            pb->is_streamed = 1;
2499
2500 e6f0deab Baptiste Coudurier
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2501
                av_free(pb);
2502
                goto fail;
2503
            }
2504 f747e6d3 Philip Gladstone
2505
            /* Now we have the actual streams */
2506 f2972c8c Baptiste Coudurier
            if (s->nb_streams != feed->nb_streams) {
2507
                av_close_input_stream(s);
2508 86771c68 Baptiste Coudurier
                av_free(pb);
2509 f747e6d3 Philip Gladstone
                goto fail;
2510
            }
2511 f2972c8c Baptiste Coudurier
2512 cb51aef1 Baptiste Coudurier
            for (i = 0; i < s->nb_streams; i++) {
2513
                AVStream *fst = feed->streams[i];
2514
                AVStream *st = s->streams[i];
2515
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2516
                if (fst->codec->extradata_size) {
2517
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2518
                    if (!fst->codec->extradata)
2519
                        goto fail;
2520
                    memcpy(fst->codec->extradata, st->codec->extradata,
2521
                           fst->codec->extradata_size);
2522
                }
2523
            }
2524 f2972c8c Baptiste Coudurier
2525
            av_close_input_stream(s);
2526 86771c68 Baptiste Coudurier
            av_free(pb);
2527 85f07f22 Fabrice Bellard
        }
2528
        c->buffer_ptr = c->buffer;
2529
    }
2530
2531
    return 0;
2532
 fail:
2533
    c->stream->feed_opened = 0;
2534
    close(c->feed_fd);
2535 c1593d0e Baptiste Coudurier
    /* wake up any waiting connections to stop waiting for feed */
2536
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2537
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2538
            c1->stream->feed == c->stream->feed)
2539
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2540
    }
2541 85f07f22 Fabrice Bellard
    return -1;
2542
}
2543
2544 2effd274 Fabrice Bellard
/********************************************************************/
2545
/* RTSP handling */
2546
2547
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2548
{
2549
    const char *str;
2550
    time_t ti;
2551
    char *p;
2552
    char buf2[32];
2553
2554
    switch(error_number) {
2555 7e665cd3 Luca Abeni
    case RTSP_STATUS_OK:
2556
        str = "OK";
2557
        break;
2558
    case RTSP_STATUS_METHOD:
2559
        str = "Method Not Allowed";
2560
        break;
2561
    case RTSP_STATUS_BANDWIDTH:
2562
        str = "Not Enough Bandwidth";
2563
        break;
2564
    case RTSP_STATUS_SESSION:
2565
        str = "Session Not Found";
2566
        break;
2567
    case RTSP_STATUS_STATE:
2568
        str = "Method Not Valid in This State";
2569
        break;
2570
    case RTSP_STATUS_AGGREGATE:
2571
        str = "Aggregate operation not allowed";
2572
        break;
2573
    case RTSP_STATUS_ONLY_AGGREGATE:
2574
        str = "Only aggregate operation allowed";
2575
        break;
2576
    case RTSP_STATUS_TRANSPORT:
2577
        str = "Unsupported transport";
2578
        break;
2579
    case RTSP_STATUS_INTERNAL:
2580
        str = "Internal Server Error";
2581
        break;
2582
    case RTSP_STATUS_SERVICE:
2583
        str = "Service Unavailable";
2584
        break;
2585
    case RTSP_STATUS_VERSION:
2586
        str = "RTSP Version not supported";
2587
        break;
2588 2effd274 Fabrice Bellard
    default:
2589
        str = "Unknown Error";
2590
        break;
2591
    }
2592 115329f1 Diego Biurrun
2593 2effd274 Fabrice Bellard
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2594
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2595
2596
    /* output GMT time */
2597
    ti = time(NULL);
2598
    p = ctime(&ti);
2599
    strcpy(buf2, p);
2600
    p = buf2 + strlen(p) - 1;
2601
    if (*p == '\n')
2602
        *p = '\0';
2603
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2604
}
2605
2606
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2607
{
2608
    rtsp_reply_header(c, error_number);
2609
    url_fprintf(c->pb, "\r\n");
2610
}
2611
2612
static int rtsp_parse_request(HTTPContext *c)
2613
{
2614
    const char *p, *p1, *p2;
2615
    char cmd[32];
2616
    char url[1024];
2617
    char protocol[32];
2618
    char line[1024];
2619
    int len;
2620
    RTSPHeader header1, *header = &header1;
2621 115329f1 Diego Biurrun
2622 2effd274 Fabrice Bellard
    c->buffer_ptr[0] = '\0';
2623
    p = c->buffer;
2624 115329f1 Diego Biurrun
2625 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), &p);
2626
    get_word(url, sizeof(url), &p);
2627
    get_word(protocol, sizeof(protocol), &p);
2628
2629 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
2630
    av_strlcpy(c->url, url, sizeof(c->url));
2631
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2632 2effd274 Fabrice Bellard
2633 899681cd Björn Axelsson
    if (url_open_dyn_buf(&c->pb) < 0) {
2634 2effd274 Fabrice Bellard
        /* XXX: cannot do more */
2635
        c->pb = NULL; /* safety */
2636
        return -1;
2637
    }
2638
2639
    /* check version name */
2640
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2641
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2642
        goto the_end;
2643
    }
2644
2645
    /* parse each header line */
2646
    memset(header, 0, sizeof(RTSPHeader));
2647
    /* skip to next line */
2648
    while (*p != '\n' && *p != '\0')
2649
        p++;
2650
    if (*p == '\n')
2651
        p++;
2652
    while (*p != '\0') {
2653
        p1 = strchr(p, '\n');
2654
        if (!p1)
2655
            break;
2656
        p2 = p1;
2657
        if (p2 > p && p2[-1] == '\r')
2658
            p2--;
2659
        /* skip empty line */
2660
        if (p2 == p)
2661
            break;
2662
        len = p2 - p;
2663
        if (len > sizeof(line) - 1)
2664
            len = sizeof(line) - 1;
2665
        memcpy(line, p, len);
2666
        line[len] = '\0';
2667
        rtsp_parse_line(header, line);
2668
        p = p1 + 1;
2669
    }
2670
2671
    /* handle sequence number */
2672
    c->seq = header->seq;
2673
2674 611c5741 Alex Beregszaszi
    if (!strcmp(cmd, "DESCRIBE"))
2675 2effd274 Fabrice Bellard
        rtsp_cmd_describe(c, url);
2676 611c5741 Alex Beregszaszi
    else if (!strcmp(cmd, "OPTIONS"))
2677 0df65975 Andriy Rysin
        rtsp_cmd_options(c, url);
2678