Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ d6975eb8

History | View | Annotate | Download (150 KB)

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

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

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