Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3a74415d

History | View | Annotate | Download (152 KB)

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

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

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