Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ e0c850a8

History | View | Annotate | Download (152 KB)

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

1801 85f07f22 Fabrice Bellard
        /* feed status */
1802
        stream = first_feed;
1803
        while (stream != NULL) {
1804 2effd274 Fabrice Bellard
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1805
            url_fprintf(pb, "<TABLE>\n");
1806
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1807 85f07f22 Fabrice Bellard
            for(i=0;i<stream->nb_streams;i++) {
1808
                AVStream *st = stream->streams[i];
1809
                FeedData *fdata = st->priv_data;
1810 01f4895c Michael Niedermayer
                enc = st->codec;
1811 115329f1 Diego Biurrun

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