Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 0b006599

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

1787 85f07f22 Fabrice Bellard
        /* feed status */
1788
        stream = first_feed;
1789
        while (stream != NULL) {
1790 2effd274 Fabrice Bellard
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1791
            url_fprintf(pb, "<TABLE>\n");
1792
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1793 85f07f22 Fabrice Bellard
            for(i=0;i<stream->nb_streams;i++) {
1794
                AVStream *st = stream->streams[i];
1795
                FeedData *fdata = st->priv_data;
1796 01f4895c Michael Niedermayer
                enc = st->codec;
1797 115329f1 Diego Biurrun

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