Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 25e4f8aa

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

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

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