Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 59006372

History | View | Annotate | Download (152 KB)

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

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

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