Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 88381412

History | View | Annotate | Download (150 KB)

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

1778 85f07f22 Fabrice Bellard
        /* feed status */
1779
        stream = first_feed;
1780
        while (stream != NULL) {
1781 2effd274 Fabrice Bellard
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1782
            url_fprintf(pb, "<TABLE>\n");
1783
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1784 85f07f22 Fabrice Bellard
            for(i=0;i<stream->nb_streams;i++) {
1785
                AVStream *st = stream->streams[i];
1786
                FeedData *fdata = st->priv_data;
1787 01f4895c Michael Niedermayer
                enc = st->codec;
1788 115329f1 Diego Biurrun

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