Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 0eb4ff9e

History | View | Annotate | Download (151 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 364a9607 Diego Biurrun
22 29d3ed3b Aurelien Jacobs
#define _XOPEN_SOURCE 600
23
24 0f4e8165 Ronald S. Bultje
#include "config.h"
25 b250f9c6 Aurelien Jacobs
#if !HAVE_CLOSESOCKET
26 0f4e8165 Ronald S. Bultje
#define closesocket close
27
#endif
28
#include <string.h>
29 ea452b54 Aurelien Jacobs
#include <strings.h>
30 0f4e8165 Ronald S. Bultje
#include <stdlib.h>
31 959da985 Stefano Sabatini
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32 245976da Diego Biurrun
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35 302879cb Luca Abeni
#include "libavformat/rtpdec.h"
36 245976da Diego Biurrun
#include "libavformat/rtsp.h"
37 959da985 Stefano Sabatini
#include "libavutil/avstring.h"
38 042819c5 Baptiste Coudurier
#include "libavutil/lfg.h"
39
#include "libavutil/random_seed.h"
40 2bb6eba2 Aurelien Jacobs
#include "libavutil/intreadwrite.h"
41 7ab08864 Baptiste Coudurier
#include "libavcodec/opt.h"
42 85f07f22 Fabrice Bellard
#include <stdarg.h>
43
#include <unistd.h>
44
#include <fcntl.h>
45
#include <sys/ioctl.h>
46 b250f9c6 Aurelien Jacobs
#if HAVE_POLL_H
47 f8cda19e Luca Abeni
#include <poll.h>
48 b0c858d8 François Revol
#endif
49 85f07f22 Fabrice Bellard
#include <errno.h>
50
#include <sys/time.h>
51 4568325a Roman Shaposhnik
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
52 85f07f22 Fabrice Bellard
#include <time.h>
53 5eb765ef Philip Gladstone
#include <sys/wait.h>
54 85f07f22 Fabrice Bellard
#include <signal.h>
55 b250f9c6 Aurelien Jacobs
#if HAVE_DLFCN_H
56 2effd274 Fabrice Bellard
#include <dlfcn.h>
57 6638d424 Philip Gladstone
#endif
58 2effd274 Fabrice Bellard
59 4ce5df08 Stefano Sabatini
#include "cmdutils.h"
60 85f07f22 Fabrice Bellard
61 c367d067 Michael Niedermayer
#undef exit
62
63 64555bd9 Michael Niedermayer
const char program_name[] = "FFserver";
64 ea9c581f Stefano Sabatini
const int program_birth_year = 2000;
65 86074ed1 Stefano Sabatini
66 5a635bc7 Stefano Sabatini
static const OptionDef options[];
67
68 85f07f22 Fabrice Bellard
enum HTTPState {
69
    HTTPSTATE_WAIT_REQUEST,
70
    HTTPSTATE_SEND_HEADER,
71
    HTTPSTATE_SEND_DATA_HEADER,
72 2effd274 Fabrice Bellard
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
73 85f07f22 Fabrice Bellard
    HTTPSTATE_SEND_DATA_TRAILER,
74 115329f1 Diego Biurrun
    HTTPSTATE_RECEIVE_DATA,
75 2effd274 Fabrice Bellard
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
76
    HTTPSTATE_READY,
77
78
    RTSPSTATE_WAIT_REQUEST,
79
    RTSPSTATE_SEND_REPLY,
80 bc351386 Fabrice Bellard
    RTSPSTATE_SEND_PACKET,
81 85f07f22 Fabrice Bellard
};
82
83 9507a12e Baptiste Coudurier
static const char *http_state[] = {
84 2effd274 Fabrice Bellard
    "HTTP_WAIT_REQUEST",
85
    "HTTP_SEND_HEADER",
86
87 85f07f22 Fabrice Bellard
    "SEND_DATA_HEADER",
88
    "SEND_DATA",
89
    "SEND_DATA_TRAILER",
90
    "RECEIVE_DATA",
91
    "WAIT_FEED",
92 2effd274 Fabrice Bellard
    "READY",
93
94
    "RTSP_WAIT_REQUEST",
95
    "RTSP_SEND_REPLY",
96 bc351386 Fabrice Bellard
    "RTSP_SEND_PACKET",
97 85f07f22 Fabrice Bellard
};
98
99 cde25790 Philip Gladstone
#define IOBUFFER_INIT_SIZE 8192
100 85f07f22 Fabrice Bellard
101
/* timeouts are in ms */
102 2effd274 Fabrice Bellard
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104
105 85f07f22 Fabrice Bellard
#define SYNC_TIMEOUT (10 * 1000)
106
107 b516ecdd Ronald S. Bultje
typedef struct RTSPActionServerSetup {
108
    uint32_t ipaddr;
109
    char transport_option[512];
110
} RTSPActionServerSetup;
111
112 5eb765ef Philip Gladstone
typedef struct {
113 0c1a9eda Zdenek Kabelac
    int64_t count1, count2;
114 c3f58185 Alex Beregszaszi
    int64_t time1, time2;
115 5eb765ef Philip Gladstone
} DataRateData;
116
117 85f07f22 Fabrice Bellard
/* context associated with one connection */
118
typedef struct HTTPContext {
119
    enum HTTPState state;
120
    int fd; /* socket file descriptor */
121
    struct sockaddr_in from_addr; /* origin */
122
    struct pollfd *poll_entry; /* used when polling */
123 c3f58185 Alex Beregszaszi
    int64_t timeout;
124 0c1a9eda Zdenek Kabelac
    uint8_t *buffer_ptr, *buffer_end;
125 85f07f22 Fabrice Bellard
    int http_error;
126 edfdd798 Alex Beregszaszi
    int post;
127 85f07f22 Fabrice Bellard
    struct HTTPContext *next;
128 42a63c6a Philip Gladstone
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
129 0c1a9eda Zdenek Kabelac
    int64_t data_count;
130 85f07f22 Fabrice Bellard
    /* feed input */
131
    int feed_fd;
132
    /* input format handling */
133
    AVFormatContext *fmt_in;
134 c3f58185 Alex Beregszaszi
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
135 0c1a9eda Zdenek Kabelac
    int64_t first_pts;            /* initial pts value */
136 e240a0bb Fabrice Bellard
    int64_t cur_pts;             /* current pts value from the stream in us */
137
    int64_t cur_frame_duration;  /* duration of the current frame in us */
138
    int cur_frame_bytes;       /* output frame size, needed to compute
139
                                  the time at which we send each
140
                                  packet */
141
    int pts_stream_index;        /* stream we choose as clock reference */
142
    int64_t cur_clock;           /* current clock reference value in us */
143 85f07f22 Fabrice Bellard
    /* output format handling */
144
    struct FFStream *stream;
145 cde25790 Philip Gladstone
    /* -1 is invalid stream */
146
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
147
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
148
    int switch_pending;
149 2effd274 Fabrice Bellard
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
150 85f07f22 Fabrice Bellard
    int last_packet_sent; /* true if last data packet was sent */
151 7434ba6d Philip Gladstone
    int suppress_log;
152 5eb765ef Philip Gladstone
    DataRateData datarate;
153 3120d2a2 Philip Gladstone
    int wmp_client_id;
154 7434ba6d Philip Gladstone
    char protocol[16];
155
    char method[16];
156
    char url[128];
157 cde25790 Philip Gladstone
    int buffer_size;
158 0c1a9eda Zdenek Kabelac
    uint8_t *buffer;
159 2effd274 Fabrice Bellard
    int is_packetized; /* if true, the stream is packetized */
160
    int packet_stream_index; /* current stream for output in state machine */
161 115329f1 Diego Biurrun
162 2effd274 Fabrice Bellard
    /* RTSP state specific */
163 0c1a9eda Zdenek Kabelac
    uint8_t *pb_buffer; /* XXX: use that in all the code */
164 2effd274 Fabrice Bellard
    ByteIOContext *pb;
165
    int seq; /* RTSP sequence number */
166 115329f1 Diego Biurrun
167 2effd274 Fabrice Bellard
    /* RTP state specific */
168 90abbdba Ronald S. Bultje
    enum RTSPLowerTransport rtp_protocol;
169 2effd274 Fabrice Bellard
    char session_id[32]; /* session id */
170
    AVFormatContext *rtp_ctx[MAX_STREAMS];
171 e240a0bb Fabrice Bellard
172 bc351386 Fabrice Bellard
    /* RTP/UDP specific */
173
    URLContext *rtp_handles[MAX_STREAMS];
174
175
    /* RTP/TCP specific */
176
    struct HTTPContext *rtsp_c;
177
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
178 85f07f22 Fabrice Bellard
} HTTPContext;
179
180
/* each generated stream is described here */
181
enum StreamType {
182
    STREAM_TYPE_LIVE,
183
    STREAM_TYPE_STATUS,
184 cde25790 Philip Gladstone
    STREAM_TYPE_REDIRECT,
185 85f07f22 Fabrice Bellard
};
186
187 8256c0a3 Philip Gladstone
enum IPAddressAction {
188
    IP_ALLOW = 1,
189
    IP_DENY,
190
};
191
192
typedef struct IPAddressACL {
193
    struct IPAddressACL *next;
194
    enum IPAddressAction action;
195 efa04ce2 Philip Gladstone
    /* These are in host order */
196 8256c0a3 Philip Gladstone
    struct in_addr first;
197
    struct in_addr last;
198
} IPAddressACL;
199
200 85f07f22 Fabrice Bellard
/* description of each stream of the ffserver.conf file */
201
typedef struct FFStream {
202
    enum StreamType stream_type;
203
    char filename[1024];     /* stream filename */
204 2effd274 Fabrice Bellard
    struct FFStream *feed;   /* feed we are using (can be null if
205
                                coming from file) */
206 e240a0bb Fabrice Bellard
    AVFormatParameters *ap_in; /* input parameters */
207
    AVInputFormat *ifmt;       /* if non NULL, force input format */
208 bd7cf6ad Fabrice Bellard
    AVOutputFormat *fmt;
209 8256c0a3 Philip Gladstone
    IPAddressACL *acl;
210 85f07f22 Fabrice Bellard
    int nb_streams;
211 42a63c6a Philip Gladstone
    int prebuffer;      /* Number of millseconds early to start */
212 c3f58185 Alex Beregszaszi
    int64_t max_time;      /* Number of milliseconds to run */
213 79c4ea3c Philip Gladstone
    int send_on_key;
214 85f07f22 Fabrice Bellard
    AVStream *streams[MAX_STREAMS];
215
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
216
    char feed_filename[1024]; /* file name of the feed storage, or
217
                                 input file name for a stream */
218 2ac887ba Philip Gladstone
    char author[512];
219
    char title[512];
220
    char copyright[512];
221
    char comment[512];
222 cde25790 Philip Gladstone
    pid_t pid;  /* Of ffmpeg process */
223 5eb765ef Philip Gladstone
    time_t pid_start;  /* Of ffmpeg process */
224 cde25790 Philip Gladstone
    char **child_argv;
225 85f07f22 Fabrice Bellard
    struct FFStream *next;
226 177d2564 Baptiste Coudurier
    unsigned bandwidth; /* bandwidth, in kbits/s */
227 2effd274 Fabrice Bellard
    /* RTSP options */
228
    char *rtsp_option;
229 829ac53d Fabrice Bellard
    /* multicast specific */
230
    int is_multicast;
231
    struct in_addr multicast_ip;
232
    int multicast_port; /* first port used for multicast */
233 6edd6884 Fabrice Bellard
    int multicast_ttl;
234
    int loop; /* if true, send the stream in loops (only meaningful if file) */
235 829ac53d Fabrice Bellard
236 85f07f22 Fabrice Bellard
    /* feed specific */
237 2effd274 Fabrice Bellard
    int feed_opened;     /* true if someone is writing to the feed */
238 85f07f22 Fabrice Bellard
    int is_feed;         /* true if it is a feed */
239 e322ea48 Philip Gladstone
    int readonly;        /* True if writing is prohibited to the file */
240 861ec13a Baptiste Coudurier
    int truncate;        /* True if feeder connection truncate the feed file */
241 a6e14edd Philip Gladstone
    int conns_served;
242 0c1a9eda Zdenek Kabelac
    int64_t bytes_served;
243 6b0bdc75 Alex Beregszaszi
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
244 8bfb108b Diego Biurrun
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
245 0c1a9eda Zdenek Kabelac
    int64_t feed_size;          /* current size of feed */
246 85f07f22 Fabrice Bellard
    struct FFStream *next_feed;
247
} FFStream;
248
249
typedef struct FeedData {
250
    long long data_count;
251 8bfb108b Diego Biurrun
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
252 85f07f22 Fabrice Bellard
} FeedData;
253
254 18405874 Alex Beregszaszi
static struct sockaddr_in my_http_addr;
255
static struct sockaddr_in my_rtsp_addr;
256 2effd274 Fabrice Bellard
257 33f5e2ec Alex Beregszaszi
static char logfilename[1024];
258
static HTTPContext *first_http_ctx;
259
static FFStream *first_feed;   /* contains only feeds */
260
static FFStream *first_stream; /* contains all streams, including feeds */
261 85f07f22 Fabrice Bellard
262 2effd274 Fabrice Bellard
static void new_connection(int server_fd, int is_rtsp);
263
static void close_connection(HTTPContext *c);
264
265
/* HTTP handling */
266
static int handle_connection(HTTPContext *c);
267 85f07f22 Fabrice Bellard
static int http_parse_request(HTTPContext *c);
268 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c);
269 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c);
270 85f07f22 Fabrice Bellard
static int open_input_stream(HTTPContext *c, const char *info);
271
static int http_start_receive_data(HTTPContext *c);
272
static int http_receive_data(HTTPContext *c);
273 2effd274 Fabrice Bellard
274
/* RTSP handling */
275
static int rtsp_parse_request(HTTPContext *c);
276
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
277 0df65975 Andriy Rysin
static void rtsp_cmd_options(HTTPContext *c, const char *url);
278 a9e534d5 Ronald S. Bultje
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
279
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
280
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
281
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282 2effd274 Fabrice Bellard
283 829ac53d Fabrice Bellard
/* SDP handling */
284 115329f1 Diego Biurrun
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
285 829ac53d Fabrice Bellard
                                   struct in_addr my_ip);
286
287 2effd274 Fabrice Bellard
/* RTP handling */
288 115329f1 Diego Biurrun
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
289 bc351386 Fabrice Bellard
                                       FFStream *stream, const char *session_id,
290 90abbdba Ronald S. Bultje
                                       enum RTSPLowerTransport rtp_protocol);
291 115329f1 Diego Biurrun
static int rtp_new_av_stream(HTTPContext *c,
292 bc351386 Fabrice Bellard
                             int stream_index, struct sockaddr_in *dest_addr,
293
                             HTTPContext *rtsp_c);
294 85f07f22 Fabrice Bellard
295 cde25790 Philip Gladstone
static const char *my_program_name;
296 d6562d2c Philip Gladstone
static const char *my_program_dir;
297 cde25790 Philip Gladstone
298 5a635bc7 Stefano Sabatini
static const char *config_filename;
299 2ac887ba Philip Gladstone
static int ffserver_debug;
300 2effd274 Fabrice Bellard
static int ffserver_daemon;
301 2ac887ba Philip Gladstone
static int no_launch;
302 5eb765ef Philip Gladstone
static int need_to_start_children;
303 2ac887ba Philip Gladstone
304 1c9ff179 Stefano Sabatini
/* maximum number of simultaneous HTTP connections */
305
static unsigned int nb_max_http_connections = 2000;
306 4af92de6 Stefano Sabatini
static unsigned int nb_max_connections = 5;
307
static unsigned int nb_connections;
308 85f07f22 Fabrice Bellard
309 f69bb0cc Baptiste Coudurier
static uint64_t max_bandwidth = 1000;
310 1ad8289e Baptiste Coudurier
static uint64_t current_bandwidth;
311 42a63c6a Philip Gladstone
312 c3f58185 Alex Beregszaszi
static int64_t cur_time;           // Making this global saves on passing it around everywhere
313 5eb765ef Philip Gladstone
314 042819c5 Baptiste Coudurier
static AVLFG random_state;
315 1df93ae9 Alex Beregszaszi
316 85f07f22 Fabrice Bellard
static FILE *logfile = NULL;
317
318 9fd3442f Baptiste Coudurier
static char *ctime1(char *buf2)
319
{
320
    time_t ti;
321
    char *p;
322
323
    ti = time(NULL);
324
    p = ctime(&ti);
325
    strcpy(buf2, p);
326
    p = buf2 + strlen(p) - 1;
327
    if (*p == '\n')
328
        *p = '\0';
329
    return buf2;
330
}
331
332 bcd3ce59 Baptiste Coudurier
static void http_vlog(const char *fmt, va_list vargs)
333 85f07f22 Fabrice Bellard
{
334 124ed1c0 Baptiste Coudurier
    static int print_prefix = 1;
335 7434ba6d Philip Gladstone
    if (logfile) {
336 124ed1c0 Baptiste Coudurier
        if (print_prefix) {
337 9fd3442f Baptiste Coudurier
            char buf[32];
338
            ctime1(buf);
339
            fprintf(logfile, "%s ", buf);
340 124ed1c0 Baptiste Coudurier
        }
341
        print_prefix = strstr(fmt, "\n") != NULL;
342 bcd3ce59 Baptiste Coudurier
        vfprintf(logfile, fmt, vargs);
343 7434ba6d Philip Gladstone
        fflush(logfile);
344
    }
345 bcd3ce59 Baptiste Coudurier
}
346
347
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
348
{
349
    va_list vargs;
350
    va_start(vargs, fmt);
351
    http_vlog(fmt, vargs);
352
    va_end(vargs);
353
}
354
355
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
356
{
357
    static int print_prefix = 1;
358
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
359 49ceb58b Michael Niedermayer
    if (level > av_log_get_level())
360 bcd3ce59 Baptiste Coudurier
        return;
361
    if (print_prefix && avc)
362 59e7894c Baptiste Coudurier
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
363 bcd3ce59 Baptiste Coudurier
    print_prefix = strstr(fmt, "\n") != NULL;
364
    http_vlog(fmt, vargs);
365 85f07f22 Fabrice Bellard
}
366
367 6edd6884 Fabrice Bellard
static void log_connection(HTTPContext *c)
368
{
369 115329f1 Diego Biurrun
    if (c->suppress_log)
370 6edd6884 Fabrice Bellard
        return;
371
372 82e0be62 Baptiste Coudurier
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
373
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
374 6edd6884 Fabrice Bellard
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
375 cde25790 Philip Gladstone
}
376
377 0c1a9eda Zdenek Kabelac
static void update_datarate(DataRateData *drd, int64_t count)
378 5eb765ef Philip Gladstone
{
379
    if (!drd->time1 && !drd->count1) {
380
        drd->time1 = drd->time2 = cur_time;
381
        drd->count1 = drd->count2 = count;
382 eeffbdea Alex Beregszaszi
    } else if (cur_time - drd->time2 > 5000) {
383 33a4ecbe Alex Beregszaszi
        drd->time1 = drd->time2;
384
        drd->count1 = drd->count2;
385
        drd->time2 = cur_time;
386
        drd->count2 = count;
387 5eb765ef Philip Gladstone
    }
388
}
389
390
/* In bytes per second */
391 0c1a9eda Zdenek Kabelac
static int compute_datarate(DataRateData *drd, int64_t count)
392 5eb765ef Philip Gladstone
{
393
    if (cur_time == drd->time1)
394
        return 0;
395 115329f1 Diego Biurrun
396 5eb765ef Philip Gladstone
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
397
}
398
399 a782f209 Philip Gladstone
400 cde25790 Philip Gladstone
static void start_children(FFStream *feed)
401
{
402 2ac887ba Philip Gladstone
    if (no_launch)
403
        return;
404
405 cde25790 Philip Gladstone
    for (; feed; feed = feed->next) {
406 5eb765ef Philip Gladstone
        if (feed->child_argv && !feed->pid) {
407
            feed->pid_start = time(0);
408
409 cde25790 Philip Gladstone
            feed->pid = fork();
410
411
            if (feed->pid < 0) {
412 b4befb99 Baptiste Coudurier
                http_log("Unable to create children\n");
413 cde25790 Philip Gladstone
                exit(1);
414
            }
415
            if (!feed->pid) {
416
                /* In child */
417
                char pathname[1024];
418
                char *slash;
419
                int i;
420
421 40444a59 Stefano Sabatini
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
422
423
                slash = strrchr(pathname, '/');
424
                if (!slash)
425
                    slash = pathname;
426
                else
427
                    slash++;
428
                strcpy(slash, "ffmpeg");
429
430 8bf61f5b Stefano Sabatini
                http_log("Launch commandline: ");
431
                http_log("%s ", pathname);
432
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
433
                    http_log("%s ", feed->child_argv[i]);
434
                http_log("\n");
435 40444a59 Stefano Sabatini
436 611c5741 Alex Beregszaszi
                for (i = 3; i < 256; i++)
437 5eb765ef Philip Gladstone
                    close(i);
438 cde25790 Philip Gladstone
439 5eb765ef Philip Gladstone
                if (!ffserver_debug) {
440 2ac887ba Philip Gladstone
                    i = open("/dev/null", O_RDWR);
441 3296409d Baptiste Coudurier
                    if (i != -1) {
442 2ac887ba Philip Gladstone
                        dup2(i, 0);
443 3296409d Baptiste Coudurier
                        dup2(i, 1);
444
                        dup2(i, 2);
445 5eb765ef Philip Gladstone
                        close(i);
446 3296409d Baptiste Coudurier
                    }
447 2ac887ba Philip Gladstone
                }
448 cde25790 Philip Gladstone
449 d6562d2c Philip Gladstone
                /* This is needed to make relative pathnames work */
450
                chdir(my_program_dir);
451
452 a4d70941 Philip Gladstone
                signal(SIGPIPE, SIG_DFL);
453
454 cde25790 Philip Gladstone
                execvp(pathname, feed->child_argv);
455
456
                _exit(1);
457
            }
458
        }
459
    }
460 7434ba6d Philip Gladstone
}
461
462 2effd274 Fabrice Bellard
/* open a listening socket */
463
static int socket_open_listen(struct sockaddr_in *my_addr)
464 85f07f22 Fabrice Bellard
{
465 2effd274 Fabrice Bellard
    int server_fd, tmp;
466 85f07f22 Fabrice Bellard
467
    server_fd = socket(AF_INET,SOCK_STREAM,0);
468
    if (server_fd < 0) {
469
        perror ("socket");
470
        return -1;
471
    }
472 115329f1 Diego Biurrun
473 85f07f22 Fabrice Bellard
    tmp = 1;
474
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
475
476 2effd274 Fabrice Bellard
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
477 b17d099d Philip Gladstone
        char bindmsg[32];
478
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
479
        perror (bindmsg);
480 d96633bb Alex Beregszaszi
        closesocket(server_fd);
481 85f07f22 Fabrice Bellard
        return -1;
482
    }
483 115329f1 Diego Biurrun
484 85f07f22 Fabrice Bellard
    if (listen (server_fd, 5) < 0) {
485
        perror ("listen");
486 d96633bb Alex Beregszaszi
        closesocket(server_fd);
487 85f07f22 Fabrice Bellard
        return -1;
488
    }
489 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(server_fd, 1);
490 2effd274 Fabrice Bellard
491
    return server_fd;
492
}
493
494 6edd6884 Fabrice Bellard
/* start all multicast streams */
495
static void start_multicast(void)
496
{
497
    FFStream *stream;
498
    char session_id[32];
499
    HTTPContext *rtp_c;
500
    struct sockaddr_in dest_addr;
501
    int default_port, stream_index;
502
503
    default_port = 6000;
504
    for(stream = first_stream; stream != NULL; stream = stream->next) {
505
        if (stream->is_multicast) {
506
            /* open the RTP connection */
507 1df93ae9 Alex Beregszaszi
            snprintf(session_id, sizeof(session_id), "%08x%08x",
508 042819c5 Baptiste Coudurier
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
509 6edd6884 Fabrice Bellard
510
            /* choose a port if none given */
511
            if (stream->multicast_port == 0) {
512
                stream->multicast_port = default_port;
513
                default_port += 100;
514
            }
515
516
            dest_addr.sin_family = AF_INET;
517
            dest_addr.sin_addr = stream->multicast_ip;
518
            dest_addr.sin_port = htons(stream->multicast_port);
519
520 115329f1 Diego Biurrun
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521 90abbdba Ronald S. Bultje
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
522 611c5741 Alex Beregszaszi
            if (!rtp_c)
523 6edd6884 Fabrice Bellard
                continue;
524 611c5741 Alex Beregszaszi
525 6edd6884 Fabrice Bellard
            if (open_input_stream(rtp_c, "") < 0) {
526 b4befb99 Baptiste Coudurier
                http_log("Could not open input stream for stream '%s'\n",
527
                         stream->filename);
528 6edd6884 Fabrice Bellard
                continue;
529
            }
530
531
            /* open each RTP stream */
532 115329f1 Diego Biurrun
            for(stream_index = 0; stream_index < stream->nb_streams;
533 6edd6884 Fabrice Bellard
                stream_index++) {
534 115329f1 Diego Biurrun
                dest_addr.sin_port = htons(stream->multicast_port +
535 6edd6884 Fabrice Bellard
                                           2 * stream_index);
536 bc351386 Fabrice Bellard
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
537 b4befb99 Baptiste Coudurier
                    http_log("Could not open output stream '%s/streamid=%d'\n",
538
                             stream->filename, stream_index);
539 0fa45e19 Fabrice Bellard
                    exit(1);
540 6edd6884 Fabrice Bellard
                }
541
            }
542
543
            /* change state to send data */
544
            rtp_c->state = HTTPSTATE_SEND_DATA;
545
        }
546
    }
547
}
548 2effd274 Fabrice Bellard
549
/* main loop of the http server */
550
static int http_server(void)
551
{
552 d2a1ea1d Baptiste Coudurier
    int server_fd = 0, rtsp_server_fd = 0;
553
    int ret, delay, delay1;
554 1c9ff179 Stefano Sabatini
    struct pollfd *poll_table, *poll_entry;
555 2effd274 Fabrice Bellard
    HTTPContext *c, *c_next;
556
557 a7f361eb Baptiste Coudurier
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
558 1c9ff179 Stefano Sabatini
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
559
        return -1;
560
    }
561
562 d2a1ea1d Baptiste Coudurier
    if (my_http_addr.sin_port) {
563 2b9cd1e7 Baptiste Coudurier
        server_fd = socket_open_listen(&my_http_addr);
564
        if (server_fd < 0)
565
            return -1;
566 d2a1ea1d Baptiste Coudurier
    }
567 85f07f22 Fabrice Bellard
568 d2a1ea1d Baptiste Coudurier
    if (my_rtsp_addr.sin_port) {
569 2b9cd1e7 Baptiste Coudurier
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
570
        if (rtsp_server_fd < 0)
571
            return -1;
572 d2a1ea1d Baptiste Coudurier
    }
573
574
    if (!rtsp_server_fd && !server_fd) {
575
        http_log("HTTP and RTSP disabled.\n");
576
        return -1;
577
    }
578 115329f1 Diego Biurrun
579 a3341b9d Baptiste Coudurier
    http_log("FFserver started.\n");
580 85f07f22 Fabrice Bellard
581 cde25790 Philip Gladstone
    start_children(first_feed);
582
583 6edd6884 Fabrice Bellard
    start_multicast();
584
585 85f07f22 Fabrice Bellard
    for(;;) {
586
        poll_entry = poll_table;
587 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
588 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = server_fd;
589
            poll_entry->events = POLLIN;
590
            poll_entry++;
591 d2a1ea1d Baptiste Coudurier
        }
592
        if (rtsp_server_fd) {
593 2b9cd1e7 Baptiste Coudurier
            poll_entry->fd = rtsp_server_fd;
594
            poll_entry->events = POLLIN;
595
            poll_entry++;
596 d2a1ea1d Baptiste Coudurier
        }
597 2effd274 Fabrice Bellard
598 85f07f22 Fabrice Bellard
        /* wait for events on each HTTP handle */
599
        c = first_http_ctx;
600 2effd274 Fabrice Bellard
        delay = 1000;
601 85f07f22 Fabrice Bellard
        while (c != NULL) {
602
            int fd;
603
            fd = c->fd;
604
            switch(c->state) {
605 2effd274 Fabrice Bellard
            case HTTPSTATE_SEND_HEADER:
606
            case RTSPSTATE_SEND_REPLY:
607 bc351386 Fabrice Bellard
            case RTSPSTATE_SEND_PACKET:
608 85f07f22 Fabrice Bellard
                c->poll_entry = poll_entry;
609
                poll_entry->fd = fd;
610 2effd274 Fabrice Bellard
                poll_entry->events = POLLOUT;
611 85f07f22 Fabrice Bellard
                poll_entry++;
612
                break;
613
            case HTTPSTATE_SEND_DATA_HEADER:
614
            case HTTPSTATE_SEND_DATA:
615
            case HTTPSTATE_SEND_DATA_TRAILER:
616 2effd274 Fabrice Bellard
                if (!c->is_packetized) {
617
                    /* for TCP, we output as much as we can (may need to put a limit) */
618
                    c->poll_entry = poll_entry;
619
                    poll_entry->fd = fd;
620
                    poll_entry->events = POLLOUT;
621
                    poll_entry++;
622
                } else {
623 e240a0bb Fabrice Bellard
                    /* when ffserver is doing the timing, we work by
624
                       looking at which packet need to be sent every
625
                       10 ms */
626
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
627
                    if (delay1 < delay)
628
                        delay = delay1;
629 2effd274 Fabrice Bellard
                }
630 85f07f22 Fabrice Bellard
                break;
631 2effd274 Fabrice Bellard
            case HTTPSTATE_WAIT_REQUEST:
632 85f07f22 Fabrice Bellard
            case HTTPSTATE_RECEIVE_DATA:
633
            case HTTPSTATE_WAIT_FEED:
634 2effd274 Fabrice Bellard
            case RTSPSTATE_WAIT_REQUEST:
635 85f07f22 Fabrice Bellard
                /* need to catch errors */
636
                c->poll_entry = poll_entry;
637
                poll_entry->fd = fd;
638 a6e14edd Philip Gladstone
                poll_entry->events = POLLIN;/* Maybe this will work */
639 85f07f22 Fabrice Bellard
                poll_entry++;
640
                break;
641
            default:
642
                c->poll_entry = NULL;
643
                break;
644
            }
645
            c = c->next;
646
        }
647
648
        /* wait for an event on one connection. We poll at least every
649
           second to handle timeouts */
650
        do {
651 2effd274 Fabrice Bellard
            ret = poll(poll_table, poll_entry - poll_table, delay);
652 8da4034f Alex Beregszaszi
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
653
                ff_neterrno() != FF_NETERROR(EINTR))
654 53e2f9ca Michael Niedermayer
                return -1;
655 e8d658df Luca Abeni
        } while (ret < 0);
656 115329f1 Diego Biurrun
657 c3f58185 Alex Beregszaszi
        cur_time = av_gettime() / 1000;
658 85f07f22 Fabrice Bellard
659 5eb765ef Philip Gladstone
        if (need_to_start_children) {
660
            need_to_start_children = 0;
661
            start_children(first_feed);
662
        }
663
664 85f07f22 Fabrice Bellard
        /* now handle the events */
665 2effd274 Fabrice Bellard
        for(c = first_http_ctx; c != NULL; c = c_next) {
666
            c_next = c->next;
667
            if (handle_connection(c) < 0) {
668 85f07f22 Fabrice Bellard
                /* close and free the connection */
669 7434ba6d Philip Gladstone
                log_connection(c);
670 2effd274 Fabrice Bellard
                close_connection(c);
671 85f07f22 Fabrice Bellard
            }
672
        }
673
674
        poll_entry = poll_table;
675 d2a1ea1d Baptiste Coudurier
        if (server_fd) {
676 2b9cd1e7 Baptiste Coudurier
            /* new HTTP connection request ? */
677
            if (poll_entry->revents & POLLIN)
678
                new_connection(server_fd, 0);
679
            poll_entry++;
680 d2a1ea1d Baptiste Coudurier
        }
681
        if (rtsp_server_fd) {
682 2b9cd1e7 Baptiste Coudurier
            /* new RTSP connection request ? */
683
            if (poll_entry->revents & POLLIN)
684
                new_connection(rtsp_server_fd, 1);
685 d2a1ea1d Baptiste Coudurier
        }
686 85f07f22 Fabrice Bellard
    }
687
}
688
689 2effd274 Fabrice Bellard
/* start waiting for a new HTTP/RTSP request */
690
static void start_wait_request(HTTPContext *c, int is_rtsp)
691 85f07f22 Fabrice Bellard
{
692 2effd274 Fabrice Bellard
    c->buffer_ptr = c->buffer;
693
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
694
695
    if (is_rtsp) {
696
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
697
        c->state = RTSPSTATE_WAIT_REQUEST;
698
    } else {
699
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
700
        c->state = HTTPSTATE_WAIT_REQUEST;
701
    }
702
}
703
704 0bdd8b85 Baptiste Coudurier
static void http_send_too_busy_reply(int fd)
705
{
706
    char buffer[300];
707
    int len = snprintf(buffer, sizeof(buffer),
708
                       "HTTP/1.0 200 Server too busy\r\n"
709
                       "Content-type: text/html\r\n"
710
                       "\r\n"
711
                       "<html><head><title>Too busy</title></head><body>\r\n"
712
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
713
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
714
                       "</body></html>\r\n",
715
                       nb_connections, nb_max_connections);
716
    send(fd, buffer, len, 0);
717
}
718
719
720 2effd274 Fabrice Bellard
static void new_connection(int server_fd, int is_rtsp)
721
{
722
    struct sockaddr_in from_addr;
723
    int fd, len;
724
    HTTPContext *c = NULL;
725
726
    len = sizeof(from_addr);
727 115329f1 Diego Biurrun
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
728 2effd274 Fabrice Bellard
                &len);
729 050056d0 Baptiste Coudurier
    if (fd < 0) {
730
        http_log("error during accept %s\n", strerror(errno));
731 2effd274 Fabrice Bellard
        return;
732 050056d0 Baptiste Coudurier
    }
733 ba472aaf Alex Beregszaszi
    ff_socket_nonblock(fd, 1);
734 2effd274 Fabrice Bellard
735 0bdd8b85 Baptiste Coudurier
    if (nb_connections >= nb_max_connections) {
736
        http_send_too_busy_reply(fd);
737 2effd274 Fabrice Bellard
        goto fail;
738 0bdd8b85 Baptiste Coudurier
    }
739 115329f1 Diego Biurrun
740 2effd274 Fabrice Bellard
    /* add a new connection */
741
    c = av_mallocz(sizeof(HTTPContext));
742
    if (!c)
743
        goto fail;
744 115329f1 Diego Biurrun
745 2effd274 Fabrice Bellard
    c->fd = fd;
746
    c->poll_entry = NULL;
747
    c->from_addr = from_addr;
748
    c->buffer_size = IOBUFFER_INIT_SIZE;
749
    c->buffer = av_malloc(c->buffer_size);
750
    if (!c->buffer)
751
        goto fail;
752 8bc80f8b Philip Gladstone
753
    c->next = first_http_ctx;
754
    first_http_ctx = c;
755 2effd274 Fabrice Bellard
    nb_connections++;
756 115329f1 Diego Biurrun
757 2effd274 Fabrice Bellard
    start_wait_request(c, is_rtsp);
758
759
    return;
760
761
 fail:
762
    if (c) {
763
        av_free(c->buffer);
764
        av_free(c);
765
    }
766 d96633bb Alex Beregszaszi
    closesocket(fd);
767 2effd274 Fabrice Bellard
}
768
769
static void close_connection(HTTPContext *c)
770
{
771
    HTTPContext **cp, *c1;
772
    int i, nb_streams;
773
    AVFormatContext *ctx;
774
    URLContext *h;
775
    AVStream *st;
776
777
    /* remove connection from list */
778
    cp = &first_http_ctx;
779
    while ((*cp) != NULL) {
780
        c1 = *cp;
781 611c5741 Alex Beregszaszi
        if (c1 == c)
782 2effd274 Fabrice Bellard
            *cp = c->next;
783 611c5741 Alex Beregszaszi
        else
784 2effd274 Fabrice Bellard
            cp = &c1->next;
785
    }
786
787 bc351386 Fabrice Bellard
    /* remove references, if any (XXX: do it faster) */
788
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
789
        if (c1->rtsp_c == c)
790
            c1->rtsp_c = NULL;
791
    }
792
793 2effd274 Fabrice Bellard
    /* remove connection associated resources */
794
    if (c->fd >= 0)
795 d96633bb Alex Beregszaszi
        closesocket(c->fd);
796 2effd274 Fabrice Bellard
    if (c->fmt_in) {
797
        /* close each frame parser */
798
        for(i=0;i<c->fmt_in->nb_streams;i++) {
799
            st = c->fmt_in->streams[i];
800 611c5741 Alex Beregszaszi
            if (st->codec->codec)
801 01f4895c Michael Niedermayer
                avcodec_close(st->codec);
802 2effd274 Fabrice Bellard
        }
803
        av_close_input_file(c->fmt_in);
804
    }
805
806
    /* free RTP output streams if any */
807
    nb_streams = 0;
808 115329f1 Diego Biurrun
    if (c->stream)
809 2effd274 Fabrice Bellard
        nb_streams = c->stream->nb_streams;
810 115329f1 Diego Biurrun
811 2effd274 Fabrice Bellard
    for(i=0;i<nb_streams;i++) {
812
        ctx = c->rtp_ctx[i];
813
        if (ctx) {
814
            av_write_trailer(ctx);
815
            av_free(ctx);
816
        }
817
        h = c->rtp_handles[i];
818 611c5741 Alex Beregszaszi
        if (h)
819 2effd274 Fabrice Bellard
            url_close(h);
820
    }
821 115329f1 Diego Biurrun
822 b88ba823 Mark Hills
    ctx = &c->fmt_ctx;
823
824 637b638e Baptiste Coudurier
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
825 87638494 Philip Gladstone
        if (ctx->oformat) {
826
            /* prepare header */
827
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
828
                av_write_trailer(ctx);
829 f8b06be9 Baptiste Coudurier
                av_freep(&c->pb_buffer);
830 899681cd Björn Axelsson
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
831 87638494 Philip Gladstone
            }
832
        }
833
    }
834
835 115329f1 Diego Biurrun
    for(i=0; i<ctx->nb_streams; i++)
836 0bd53967 Alex Beregszaszi
        av_free(ctx->streams[i]);
837 f0ef6240 Philip Gladstone
838 edfdd798 Alex Beregszaszi
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
839 6edd6884 Fabrice Bellard
        current_bandwidth -= c->stream->bandwidth;
840 5400e092 Alex Beregszaszi
841
    /* signal that there is no feed if we are the feeder socket */
842
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
843
        c->stream->feed_opened = 0;
844
        close(c->feed_fd);
845
    }
846
847 2effd274 Fabrice Bellard
    av_freep(&c->pb_buffer);
848 bc351386 Fabrice Bellard
    av_freep(&c->packet_buffer);
849 2effd274 Fabrice Bellard
    av_free(c->buffer);
850
    av_free(c);
851
    nb_connections--;
852
}
853
854
static int handle_connection(HTTPContext *c)
855
{
856
    int len, ret;
857 115329f1 Diego Biurrun
858 85f07f22 Fabrice Bellard
    switch(c->state) {
859
    case HTTPSTATE_WAIT_REQUEST:
860 2effd274 Fabrice Bellard
    case RTSPSTATE_WAIT_REQUEST:
861 85f07f22 Fabrice Bellard
        /* timeout ? */
862
        if ((c->timeout - cur_time) < 0)
863
            return -1;
864
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
865
            return -1;
866
867
        /* no need to read if no events */
868
        if (!(c->poll_entry->revents & POLLIN))
869
            return 0;
870
        /* read the data */
871 1bc1cfdd Giancarlo Formicuccia
    read_loop:
872 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, 1, 0);
873 85f07f22 Fabrice Bellard
        if (len < 0) {
874 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
875
                ff_neterrno() != FF_NETERROR(EINTR))
876 85f07f22 Fabrice Bellard
                return -1;
877
        } else if (len == 0) {
878
            return -1;
879
        } else {
880 94d9ad5f Giancarlo Formicuccia
            /* search for end of request. */
881 0c1a9eda Zdenek Kabelac
            uint8_t *ptr;
882 85f07f22 Fabrice Bellard
            c->buffer_ptr += len;
883
            ptr = c->buffer_ptr;
884
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
885
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
886
                /* request found : parse it and reply */
887 2effd274 Fabrice Bellard
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
888
                    ret = http_parse_request(c);
889
                } else {
890
                    ret = rtsp_parse_request(c);
891
                }
892
                if (ret < 0)
893 85f07f22 Fabrice Bellard
                    return -1;
894
            } else if (ptr >= c->buffer_end) {
895
                /* request too long: cannot do anything */
896
                return -1;
897 1bc1cfdd Giancarlo Formicuccia
            } else goto read_loop;
898 85f07f22 Fabrice Bellard
        }
899
        break;
900
901
    case HTTPSTATE_SEND_HEADER:
902
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
903
            return -1;
904
905 2effd274 Fabrice Bellard
        /* no need to write if no events */
906 85f07f22 Fabrice Bellard
        if (!(c->poll_entry->revents & POLLOUT))
907
            return 0;
908 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
909 85f07f22 Fabrice Bellard
        if (len < 0) {
910 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
911
                ff_neterrno() != FF_NETERROR(EINTR)) {
912 85f07f22 Fabrice Bellard
                /* error : close connection */
913 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
914 85f07f22 Fabrice Bellard
                return -1;
915
            }
916
        } else {
917
            c->buffer_ptr += len;
918 2e04edb3 Philip Gladstone
            if (c->stream)
919
                c->stream->bytes_served += len;
920 a6e14edd Philip Gladstone
            c->data_count += len;
921 85f07f22 Fabrice Bellard
            if (c->buffer_ptr >= c->buffer_end) {
922 2effd274 Fabrice Bellard
                av_freep(&c->pb_buffer);
923 85f07f22 Fabrice Bellard
                /* if error, exit */
924 611c5741 Alex Beregszaszi
                if (c->http_error)
925 85f07f22 Fabrice Bellard
                    return -1;
926 2effd274 Fabrice Bellard
                /* all the buffer was sent : synchronize to the incoming stream */
927 85f07f22 Fabrice Bellard
                c->state = HTTPSTATE_SEND_DATA_HEADER;
928
                c->buffer_ptr = c->buffer_end = c->buffer;
929
            }
930
        }
931
        break;
932
933
    case HTTPSTATE_SEND_DATA:
934
    case HTTPSTATE_SEND_DATA_HEADER:
935
    case HTTPSTATE_SEND_DATA_TRAILER:
936 2effd274 Fabrice Bellard
        /* for packetized output, we consider we can always write (the
937
           input streams sets the speed). It may be better to verify
938
           that we do not rely too much on the kernel queues */
939
        if (!c->is_packetized) {
940
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
941
                return -1;
942 115329f1 Diego Biurrun
943 2effd274 Fabrice Bellard
            /* no need to read if no events */
944
            if (!(c->poll_entry->revents & POLLOUT))
945
                return 0;
946
        }
947 5eb765ef Philip Gladstone
        if (http_send_data(c) < 0)
948 85f07f22 Fabrice Bellard
            return -1;
949 638831aa Alex Beregszaszi
        /* close connection if trailer sent */
950
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
951
            return -1;
952 85f07f22 Fabrice Bellard
        break;
953
    case HTTPSTATE_RECEIVE_DATA:
954
        /* no need to read if no events */
955
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
956
            return -1;
957
        if (!(c->poll_entry->revents & POLLIN))
958
            return 0;
959
        if (http_receive_data(c) < 0)
960
            return -1;
961
        break;
962
    case HTTPSTATE_WAIT_FEED:
963
        /* no need to read if no events */
964 a6e14edd Philip Gladstone
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
965 85f07f22 Fabrice Bellard
            return -1;
966
967
        /* nothing to do, we'll be waken up by incoming feed packets */
968
        break;
969 2effd274 Fabrice Bellard
970
    case RTSPSTATE_SEND_REPLY:
971
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
972
            av_freep(&c->pb_buffer);
973
            return -1;
974
        }
975
        /* no need to write if no events */
976
        if (!(c->poll_entry->revents & POLLOUT))
977
            return 0;
978 c60202df Alex Beregszaszi
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
979 2effd274 Fabrice Bellard
        if (len < 0) {
980 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
981
                ff_neterrno() != FF_NETERROR(EINTR)) {
982 2effd274 Fabrice Bellard
                /* error : close connection */
983
                av_freep(&c->pb_buffer);
984
                return -1;
985
            }
986
        } else {
987
            c->buffer_ptr += len;
988
            c->data_count += len;
989
            if (c->buffer_ptr >= c->buffer_end) {
990
                /* all the buffer was sent : wait for a new request */
991
                av_freep(&c->pb_buffer);
992
                start_wait_request(c, 1);
993
            }
994
        }
995
        break;
996 bc351386 Fabrice Bellard
    case RTSPSTATE_SEND_PACKET:
997
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
998
            av_freep(&c->packet_buffer);
999
            return -1;
1000
        }
1001
        /* no need to write if no events */
1002
        if (!(c->poll_entry->revents & POLLOUT))
1003
            return 0;
1004 c60202df Alex Beregszaszi
        len = send(c->fd, c->packet_buffer_ptr,
1005
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1006 bc351386 Fabrice Bellard
        if (len < 0) {
1007 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1008
                ff_neterrno() != FF_NETERROR(EINTR)) {
1009 bc351386 Fabrice Bellard
                /* error : close connection */
1010
                av_freep(&c->packet_buffer);
1011
                return -1;
1012
            }
1013
        } else {
1014
            c->packet_buffer_ptr += len;
1015
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1016
                /* all the buffer was sent : wait for a new request */
1017
                av_freep(&c->packet_buffer);
1018
                c->state = RTSPSTATE_WAIT_REQUEST;
1019
            }
1020
        }
1021
        break;
1022 2effd274 Fabrice Bellard
    case HTTPSTATE_READY:
1023
        /* nothing to do */
1024
        break;
1025 85f07f22 Fabrice Bellard
    default:
1026
        return -1;
1027
    }
1028
    return 0;
1029
}
1030
1031 3120d2a2 Philip Gladstone
static int extract_rates(char *rates, int ratelen, const char *request)
1032
{
1033
    const char *p;
1034
1035
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1036
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1037
            const char *q = p + 7;
1038
1039
            while (*q && *q != '\n' && isspace(*q))
1040
                q++;
1041
1042
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1043
                int stream_no;
1044
                int rate_no;
1045
1046
                q += 20;
1047
1048 cde25790 Philip Gladstone
                memset(rates, 0xff, ratelen);
1049 3120d2a2 Philip Gladstone
1050
                while (1) {
1051
                    while (*q && *q != '\n' && *q != ':')
1052
                        q++;
1053
1054 611c5741 Alex Beregszaszi
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1055 3120d2a2 Philip Gladstone
                        break;
1056 611c5741 Alex Beregszaszi
1057 3120d2a2 Philip Gladstone
                    stream_no--;
1058 611c5741 Alex Beregszaszi
                    if (stream_no < ratelen && stream_no >= 0)
1059 3120d2a2 Philip Gladstone
                        rates[stream_no] = rate_no;
1060
1061
                    while (*q && *q != '\n' && !isspace(*q))
1062
                        q++;
1063
                }
1064
1065
                return 1;
1066
            }
1067
        }
1068
        p = strchr(p, '\n');
1069
        if (!p)
1070
            break;
1071
1072
        p++;
1073
    }
1074
1075
    return 0;
1076
}
1077
1078 cde25790 Philip Gladstone
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1079 3120d2a2 Philip Gladstone
{
1080
    int i;
1081 cde25790 Philip Gladstone
    int best_bitrate = 100000000;
1082
    int best = -1;
1083
1084
    for (i = 0; i < feed->nb_streams; i++) {
1085 01f4895c Michael Niedermayer
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1086 cde25790 Philip Gladstone
1087
        if (feed_codec->codec_id != codec->codec_id ||
1088
            feed_codec->sample_rate != codec->sample_rate ||
1089
            feed_codec->width != codec->width ||
1090 611c5741 Alex Beregszaszi
            feed_codec->height != codec->height)
1091 cde25790 Philip Gladstone
            continue;
1092
1093
        /* Potential stream */
1094
1095 115329f1 Diego Biurrun
        /* We want the fastest stream less than bit_rate, or the slowest
1096 cde25790 Philip Gladstone
         * faster than bit_rate
1097
         */
1098
1099
        if (feed_codec->bit_rate <= bit_rate) {
1100
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1101
                best_bitrate = feed_codec->bit_rate;
1102
                best = i;
1103
            }
1104
        } else {
1105
            if (feed_codec->bit_rate < best_bitrate) {
1106
                best_bitrate = feed_codec->bit_rate;
1107
                best = i;
1108
            }
1109
        }
1110
    }
1111
1112
    return best;
1113
}
1114
1115
static int modify_current_stream(HTTPContext *c, char *rates)
1116
{
1117
    int i;
1118
    FFStream *req = c->stream;
1119
    int action_required = 0;
1120 3120d2a2 Philip Gladstone
1121 001bcd29 Philip Gladstone
    /* Not much we can do for a feed */
1122
    if (!req->feed)
1123
        return 0;
1124
1125 3120d2a2 Philip Gladstone
    for (i = 0; i < req->nb_streams; i++) {
1126 01f4895c Michael Niedermayer
        AVCodecContext *codec = req->streams[i]->codec;
1127 3120d2a2 Philip Gladstone
1128
        switch(rates[i]) {
1129
            case 0:
1130 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = req->feed_streams[i];
1131 3120d2a2 Philip Gladstone
                break;
1132
            case 1:
1133 cde25790 Philip Gladstone
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1134 3120d2a2 Philip Gladstone
                break;
1135
            case 2:
1136 cde25790 Philip Gladstone
                /* Wants off or slow */
1137
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1138
#ifdef WANTS_OFF
1139
                /* This doesn't work well when it turns off the only stream! */
1140
                c->switch_feed_streams[i] = -2;
1141
                c->feed_streams[i] = -2;
1142
#endif
1143 3120d2a2 Philip Gladstone
                break;
1144
        }
1145
1146 cde25790 Philip Gladstone
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1147
            action_required = 1;
1148
    }
1149 3120d2a2 Philip Gladstone
1150 cde25790 Philip Gladstone
    return action_required;
1151
}
1152 3120d2a2 Philip Gladstone
1153
1154 cde25790 Philip Gladstone
static void do_switch_stream(HTTPContext *c, int i)
1155
{
1156
    if (c->switch_feed_streams[i] >= 0) {
1157 115329f1 Diego Biurrun
#ifdef PHILIP
1158 cde25790 Philip Gladstone
        c->feed_streams[i] = c->switch_feed_streams[i];
1159
#endif
1160 3120d2a2 Philip Gladstone
1161 cde25790 Philip Gladstone
        /* Now update the stream */
1162 3120d2a2 Philip Gladstone
    }
1163 cde25790 Philip Gladstone
    c->switch_feed_streams[i] = -1;
1164 3120d2a2 Philip Gladstone
}
1165 7434ba6d Philip Gladstone
1166 2effd274 Fabrice Bellard
/* XXX: factorize in utils.c ? */
1167
/* XXX: take care with different space meaning */
1168
static void skip_spaces(const char **pp)
1169
{
1170
    const char *p;
1171
    p = *pp;
1172
    while (*p == ' ' || *p == '\t')
1173
        p++;
1174
    *pp = p;
1175
}
1176
1177
static void get_word(char *buf, int buf_size, const char **pp)
1178
{
1179
    const char *p;
1180
    char *q;
1181
1182
    p = *pp;
1183
    skip_spaces(&p);
1184
    q = buf;
1185
    while (!isspace(*p) && *p != '\0') {
1186
        if ((q - buf) < buf_size - 1)
1187
            *q++ = *p;
1188
        p++;
1189
    }
1190
    if (buf_size > 0)
1191
        *q = '\0';
1192
    *pp = p;
1193
}
1194
1195 c64c0a9b Benjamin Larsson
static void get_arg(char *buf, int buf_size, const char **pp)
1196
{
1197
    const char *p;
1198
    char *q;
1199
    int quote;
1200
1201
    p = *pp;
1202
    while (isspace(*p)) p++;
1203
    q = buf;
1204
    quote = 0;
1205
    if (*p == '\"' || *p == '\'')
1206
        quote = *p++;
1207
    for(;;) {
1208
        if (quote) {
1209
            if (*p == quote)
1210
                break;
1211
        } else {
1212
            if (isspace(*p))
1213
                break;
1214
        }
1215
        if (*p == '\0')
1216
            break;
1217
        if ((q - buf) < buf_size - 1)
1218
            *q++ = *p;
1219
        p++;
1220
    }
1221
    *q = '\0';
1222
    if (quote && *p == quote)
1223
        p++;
1224
    *pp = p;
1225
}
1226
1227 8256c0a3 Philip Gladstone
static int validate_acl(FFStream *stream, HTTPContext *c)
1228
{
1229
    enum IPAddressAction last_action = IP_DENY;
1230
    IPAddressACL *acl;
1231
    struct in_addr *src = &c->from_addr.sin_addr;
1232 2bd8416e Alex Beregszaszi
    unsigned long src_addr = src->s_addr;
1233 8256c0a3 Philip Gladstone
1234
    for (acl = stream->acl; acl; acl = acl->next) {
1235 611c5741 Alex Beregszaszi
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1236 8256c0a3 Philip Gladstone
            return (acl->action == IP_ALLOW) ? 1 : 0;
1237
        last_action = acl->action;
1238
    }
1239
1240
    /* Nothing matched, so return not the last action */
1241
    return (last_action == IP_DENY) ? 1 : 0;
1242
}
1243
1244 829ac53d Fabrice Bellard
/* compute the real filename of a file by matching it without its
1245
   extensions to all the stream filenames */
1246
static void compute_real_filename(char *filename, int max_size)
1247
{
1248
    char file1[1024];
1249
    char file2[1024];
1250
    char *p;
1251
    FFStream *stream;
1252
1253
    /* compute filename by matching without the file extensions */
1254 f7d78f36 Måns Rullgård
    av_strlcpy(file1, filename, sizeof(file1));
1255 829ac53d Fabrice Bellard
    p = strrchr(file1, '.');
1256
    if (p)
1257
        *p = '\0';
1258
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1259 f7d78f36 Måns Rullgård
        av_strlcpy(file2, stream->filename, sizeof(file2));
1260 829ac53d Fabrice Bellard
        p = strrchr(file2, '.');
1261
        if (p)
1262
            *p = '\0';
1263
        if (!strcmp(file1, file2)) {
1264 f7d78f36 Måns Rullgård
            av_strlcpy(filename, stream->filename, max_size);
1265 829ac53d Fabrice Bellard
            break;
1266
        }
1267
    }
1268
}
1269
1270
enum RedirType {
1271
    REDIR_NONE,
1272
    REDIR_ASX,
1273
    REDIR_RAM,
1274
    REDIR_ASF,
1275
    REDIR_RTSP,
1276
    REDIR_SDP,
1277
};
1278
1279 85f07f22 Fabrice Bellard
/* parse http request and prepare header */
1280
static int http_parse_request(HTTPContext *c)
1281
{
1282
    char *p;
1283 829ac53d Fabrice Bellard
    enum RedirType redir_type;
1284 85f07f22 Fabrice Bellard
    char cmd[32];
1285 bae79c04 Alex Beregszaszi
    char info[1024], filename[1024];
1286 85f07f22 Fabrice Bellard
    char url[1024], *q;
1287
    char protocol[32];
1288
    char msg[1024];
1289
    const char *mime_type;
1290
    FFStream *stream;
1291 42a63c6a Philip Gladstone
    int i;
1292 3120d2a2 Philip Gladstone
    char ratebuf[32];
1293 cde25790 Philip Gladstone
    char *useragent = 0;
1294 85f07f22 Fabrice Bellard
1295
    p = c->buffer;
1296 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), (const char **)&p);
1297 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
1298 7434ba6d Philip Gladstone
1299 85f07f22 Fabrice Bellard
    if (!strcmp(cmd, "GET"))
1300 edfdd798 Alex Beregszaszi
        c->post = 0;
1301 85f07f22 Fabrice Bellard
    else if (!strcmp(cmd, "POST"))
1302 edfdd798 Alex Beregszaszi
        c->post = 1;
1303 85f07f22 Fabrice Bellard
    else
1304
        return -1;
1305
1306 2effd274 Fabrice Bellard
    get_word(url, sizeof(url), (const char **)&p);
1307 f7d78f36 Måns Rullgård
    av_strlcpy(c->url, url, sizeof(c->url));
1308 7434ba6d Philip Gladstone
1309 2effd274 Fabrice Bellard
    get_word(protocol, sizeof(protocol), (const char **)&p);
1310 85f07f22 Fabrice Bellard
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1311
        return -1;
1312 7434ba6d Philip Gladstone
1313 f7d78f36 Måns Rullgård
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1314 90f9c440 Alex Beregszaszi
1315
    if (ffserver_debug)
1316 77553ae3 Baptiste Coudurier
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1317 115329f1 Diego Biurrun
1318 85f07f22 Fabrice Bellard
    /* find the filename and the optional info string in the request */
1319 bae79c04 Alex Beregszaszi
    p = strchr(url, '?');
1320 85f07f22 Fabrice Bellard
    if (p) {
1321 f7d78f36 Måns Rullgård
        av_strlcpy(info, p, sizeof(info));
1322 85f07f22 Fabrice Bellard
        *p = '\0';
1323 611c5741 Alex Beregszaszi
    } else
1324 85f07f22 Fabrice Bellard
        info[0] = '\0';
1325
1326 f7d78f36 Måns Rullgård
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1327 bae79c04 Alex Beregszaszi
1328 cde25790 Philip Gladstone
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1329
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1330
            useragent = p + 11;
1331
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1332
                useragent++;
1333
            break;
1334
        }
1335
        p = strchr(p, '\n');
1336
        if (!p)
1337
            break;
1338
1339
        p++;
1340
    }
1341
1342 829ac53d Fabrice Bellard
    redir_type = REDIR_NONE;
1343
    if (match_ext(filename, "asx")) {
1344
        redir_type = REDIR_ASX;
1345 7434ba6d Philip Gladstone
        filename[strlen(filename)-1] = 'f';
1346 c2ce254c Philip Gladstone
    } else if (match_ext(filename, "asf") &&
1347 cde25790 Philip Gladstone
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1348
        /* if this isn't WMP or lookalike, return the redirector file */
1349 829ac53d Fabrice Bellard
        redir_type = REDIR_ASF;
1350
    } else if (match_ext(filename, "rpm,ram")) {
1351
        redir_type = REDIR_RAM;
1352 42a63c6a Philip Gladstone
        strcpy(filename + strlen(filename)-2, "m");
1353 829ac53d Fabrice Bellard
    } else if (match_ext(filename, "rtsp")) {
1354
        redir_type = REDIR_RTSP;
1355 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1356 829ac53d Fabrice Bellard
    } else if (match_ext(filename, "sdp")) {
1357
        redir_type = REDIR_SDP;
1358 bae79c04 Alex Beregszaszi
        compute_real_filename(filename, sizeof(filename) - 1);
1359 42a63c6a Philip Gladstone
    }
1360 115329f1 Diego Biurrun
1361 bae79c04 Alex Beregszaszi
    // "redirect" / request to index.html
1362
    if (!strlen(filename))
1363 f7d78f36 Måns Rullgård
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1364 bae79c04 Alex Beregszaszi
1365 85f07f22 Fabrice Bellard
    stream = first_stream;
1366
    while (stream != NULL) {
1367 8256c0a3 Philip Gladstone
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1368 85f07f22 Fabrice Bellard
            break;
1369
        stream = stream->next;
1370
    }
1371
    if (stream == NULL) {
1372 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1373 77553ae3 Baptiste Coudurier
        http_log("File '%s' not found\n", url);
1374 85f07f22 Fabrice Bellard
        goto send_error;
1375
    }
1376 42a63c6a Philip Gladstone
1377 cde25790 Philip Gladstone
    c->stream = stream;
1378
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1379
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1380
1381
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1382
        c->http_error = 301;
1383
        q = c->buffer;
1384 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1385
                      "HTTP/1.0 301 Moved\r\n"
1386
                      "Location: %s\r\n"
1387
                      "Content-type: text/html\r\n"
1388
                      "\r\n"
1389
                      "<html><head><title>Moved</title></head><body>\r\n"
1390
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1391
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1392 cde25790 Philip Gladstone
        /* prepare output buffer */
1393
        c->buffer_ptr = c->buffer;
1394
        c->buffer_end = q;
1395
        c->state = HTTPSTATE_SEND_HEADER;
1396
        return 0;
1397
    }
1398
1399 3120d2a2 Philip Gladstone
    /* If this is WMP, get the rate information */
1400
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1401 cde25790 Philip Gladstone
        if (modify_current_stream(c, ratebuf)) {
1402 37d3e066 Aurelien Jacobs
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1403 cde25790 Philip Gladstone
                if (c->switch_feed_streams[i] >= 0)
1404
                    do_switch_stream(c, i);
1405
            }
1406
        }
1407 3120d2a2 Philip Gladstone
    }
1408
1409 d8f28a77 Baptiste Coudurier
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1410
        current_bandwidth += stream->bandwidth;
1411
1412 755bfeab Diego Biurrun
    /* If already streaming this feed, do not let start another feeder. */
1413 d0a5513b Alex Beregszaszi
    if (stream->feed_opened) {
1414
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1415 77553ae3 Baptiste Coudurier
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1416 d0a5513b Alex Beregszaszi
        goto send_error;
1417
    }
1418
1419 edfdd798 Alex Beregszaszi
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1420 42a63c6a Philip Gladstone
        c->http_error = 200;
1421
        q = c->buffer;
1422 a3aa4fed Baptiste Coudurier
        q += snprintf(q, c->buffer_size,
1423
                      "HTTP/1.0 200 Server too busy\r\n"
1424
                      "Content-type: text/html\r\n"
1425
                      "\r\n"
1426
                      "<html><head><title>Too busy</title></head><body>\r\n"
1427
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1428 0be4b8d9 Baptiste Coudurier
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1429
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1430 a3aa4fed Baptiste Coudurier
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1431 42a63c6a Philip Gladstone
        /* prepare output buffer */
1432
        c->buffer_ptr = c->buffer;
1433
        c->buffer_end = q;
1434
        c->state = HTTPSTATE_SEND_HEADER;
1435
        return 0;
1436
    }
1437 115329f1 Diego Biurrun
1438 829ac53d Fabrice Bellard
    if (redir_type != REDIR_NONE) {
1439 7434ba6d Philip Gladstone
        char *hostinfo = 0;
1440 115329f1 Diego Biurrun
1441 7434ba6d Philip Gladstone
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1442
            if (strncasecmp(p, "Host:", 5) == 0) {
1443
                hostinfo = p + 5;
1444
                break;
1445
            }
1446
            p = strchr(p, '\n');
1447
            if (!p)
1448
                break;
1449
1450
            p++;
1451
        }
1452
1453
        if (hostinfo) {
1454
            char *eoh;
1455
            char hostbuf[260];
1456
1457
            while (isspace(*hostinfo))
1458
                hostinfo++;
1459
1460
            eoh = strchr(hostinfo, '\n');
1461
            if (eoh) {
1462
                if (eoh[-1] == '\r')
1463
                    eoh--;
1464
1465
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1466
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1467
                    hostbuf[eoh - hostinfo] = 0;
1468
1469
                    c->http_error = 200;
1470
                    q = c->buffer;
1471 829ac53d Fabrice Bellard
                    switch(redir_type) {
1472
                    case REDIR_ASX:
1473 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1474
                                      "HTTP/1.0 200 ASX Follows\r\n"
1475
                                      "Content-type: video/x-ms-asf\r\n"
1476
                                      "\r\n"
1477
                                      "<ASX Version=\"3\">\r\n"
1478
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1479
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1480
                                      "</ASX>\r\n", hostbuf, filename, info);
1481 829ac53d Fabrice Bellard
                        break;
1482
                    case REDIR_RAM:
1483 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1484
                                      "HTTP/1.0 200 RAM Follows\r\n"
1485
                                      "Content-type: audio/x-pn-realaudio\r\n"
1486
                                      "\r\n"
1487
                                      "# Autogenerated by ffserver\r\n"
1488
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1489 829ac53d Fabrice Bellard
                        break;
1490
                    case REDIR_ASF:
1491 a3aa4fed Baptiste Coudurier
                        q += snprintf(q, c->buffer_size,
1492
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1493
                                      "Content-type: video/x-ms-asf\r\n"
1494
                                      "\r\n"
1495
                                      "[Reference]\r\n"
1496
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1497 829ac53d Fabrice Bellard
                        break;
1498
                    case REDIR_RTSP:
1499
                        {
1500
                            char hostname[256], *p;
1501
                            /* extract only hostname */
1502 f7d78f36 Måns Rullgård
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1503 829ac53d Fabrice Bellard
                            p = strrchr(hostname, ':');
1504
                            if (p)
1505
                                *p = '\0';
1506 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1507
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1508
                                          /* XXX: incorrect mime type ? */
1509
                                          "Content-type: application/x-rtsp\r\n"
1510
                                          "\r\n"
1511
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1512 829ac53d Fabrice Bellard
                        }
1513
                        break;
1514
                    case REDIR_SDP:
1515
                        {
1516 0c1a9eda Zdenek Kabelac
                            uint8_t *sdp_data;
1517 829ac53d Fabrice Bellard
                            int sdp_data_size, len;
1518
                            struct sockaddr_in my_addr;
1519
1520 a3aa4fed Baptiste Coudurier
                            q += snprintf(q, c->buffer_size,
1521
                                          "HTTP/1.0 200 OK\r\n"
1522
                                          "Content-type: application/sdp\r\n"
1523
                                          "\r\n");
1524 829ac53d Fabrice Bellard
1525
                            len = sizeof(my_addr);
1526
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1527 115329f1 Diego Biurrun
1528 829ac53d Fabrice Bellard
                            /* XXX: should use a dynamic buffer */
1529 115329f1 Diego Biurrun
                            sdp_data_size = prepare_sdp_description(stream,
1530
                                                                    &sdp_data,
1531 829ac53d Fabrice Bellard
                                                                    my_addr.sin_addr);
1532
                            if (sdp_data_size > 0) {
1533
                                memcpy(q, sdp_data, sdp_data_size);
1534
                                q += sdp_data_size;
1535
                                *q = '\0';
1536
                                av_free(sdp_data);
1537
                            }
1538
                        }
1539
                        break;
1540
                    default:
1541 0f4e8165 Ronald S. Bultje
                        abort();
1542 829ac53d Fabrice Bellard
                        break;
1543 2effd274 Fabrice Bellard
                    }
1544 7434ba6d Philip Gladstone
1545
                    /* prepare output buffer */
1546
                    c->buffer_ptr = c->buffer;
1547
                    c->buffer_end = q;
1548
                    c->state = HTTPSTATE_SEND_HEADER;
1549
                    return 0;
1550
                }
1551
            }
1552
        }
1553
1554 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1555 7434ba6d Philip Gladstone
        goto send_error;
1556 85f07f22 Fabrice Bellard
    }
1557
1558 a6e14edd Philip Gladstone
    stream->conns_served++;
1559 7434ba6d Philip Gladstone
1560 85f07f22 Fabrice Bellard
    /* XXX: add there authenticate and IP match */
1561
1562 edfdd798 Alex Beregszaszi
    if (c->post) {
1563 85f07f22 Fabrice Bellard
        /* if post, it means a feed is being sent */
1564
        if (!stream->is_feed) {
1565 e16190fa Diego Biurrun
            /* However it might be a status report from WMP! Let us log the
1566
             * data as it might come in handy one day. */
1567 7434ba6d Philip Gladstone
            char *logline = 0;
1568 3120d2a2 Philip Gladstone
            int client_id = 0;
1569 115329f1 Diego Biurrun
1570 7434ba6d Philip Gladstone
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1571
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1572
                    logline = p;
1573
                    break;
1574
                }
1575 611c5741 Alex Beregszaszi
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1576 3120d2a2 Philip Gladstone
                    client_id = strtol(p + 18, 0, 10);
1577 7434ba6d Philip Gladstone
                p = strchr(p, '\n');
1578
                if (!p)
1579
                    break;
1580
1581
                p++;
1582
            }
1583
1584
            if (logline) {
1585
                char *eol = strchr(logline, '\n');
1586
1587
                logline += 17;
1588
1589
                if (eol) {
1590
                    if (eol[-1] == '\r')
1591
                        eol--;
1592 7906085f Falk Hüffner
                    http_log("%.*s\n", (int) (eol - logline), logline);
1593 7434ba6d Philip Gladstone
                    c->suppress_log = 1;
1594
                }
1595
            }
1596 3120d2a2 Philip Gladstone
1597 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1598
            http_log("\nGot request:\n%s\n", c->buffer);
1599 3120d2a2 Philip Gladstone
#endif
1600
1601
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1602
                HTTPContext *wmpc;
1603
1604
                /* Now we have to find the client_id */
1605
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1606
                    if (wmpc->wmp_client_id == client_id)
1607
                        break;
1608
                }
1609
1610 2d563d2f Alex Beregszaszi
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1611
                    wmpc->switch_pending = 1;
1612 3120d2a2 Philip Gladstone
            }
1613 115329f1 Diego Biurrun
1614 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "POST command not handled");
1615 cb275dd9 Philip Gladstone
            c->stream = 0;
1616 85f07f22 Fabrice Bellard
            goto send_error;
1617
        }
1618
        if (http_start_receive_data(c) < 0) {
1619 d445a7e9 Philip Gladstone
            snprintf(msg, sizeof(msg), "could not open feed");
1620 85f07f22 Fabrice Bellard
            goto send_error;
1621
        }
1622
        c->http_error = 0;
1623
        c->state = HTTPSTATE_RECEIVE_DATA;
1624
        return 0;
1625
    }
1626
1627 cde25790 Philip Gladstone
#ifdef DEBUG_WMP
1628 611c5741 Alex Beregszaszi
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1629 cde25790 Philip Gladstone
        http_log("\nGot request:\n%s\n", c->buffer);
1630 3120d2a2 Philip Gladstone
#endif
1631
1632 85f07f22 Fabrice Bellard
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1633 dca21085 Stefano Sabatini
        goto send_status;
1634 85f07f22 Fabrice Bellard
1635
    /* open input stream */
1636
    if (open_input_stream(c, info) < 0) {
1637 d445a7e9 Philip Gladstone
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1638 85f07f22 Fabrice Bellard
        goto send_error;
1639
    }
1640
1641
    /* prepare http header */
1642
    q = c->buffer;
1643 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1644 85f07f22 Fabrice Bellard
    mime_type = c->stream->fmt->mime_type;
1645
    if (!mime_type)
1646 087fa475 Alex Beregszaszi
        mime_type = "application/x-octet-stream";
1647 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1648 85f07f22 Fabrice Bellard
1649
    /* for asf, we need extra headers */
1650 8256c0a3 Philip Gladstone
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1651 3120d2a2 Philip Gladstone
        /* Need to allocate a client id */
1652
1653 042819c5 Baptiste Coudurier
        c->wmp_client_id = av_lfg_get(&random_state);
1654 3120d2a2 Philip Gladstone
1655 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);
1656 85f07f22 Fabrice Bellard
    }
1657 d445a7e9 Philip Gladstone
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1658
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1659 115329f1 Diego Biurrun
1660 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1661
    c->http_error = 0;
1662
    c->buffer_ptr = c->buffer;
1663
    c->buffer_end = q;
1664
    c->state = HTTPSTATE_SEND_HEADER;
1665
    return 0;
1666
 send_error:
1667
    c->http_error = 404;
1668
    q = c->buffer;
1669 a3aa4fed Baptiste Coudurier
    q += snprintf(q, c->buffer_size,
1670
                  "HTTP/1.0 404 Not Found\r\n"
1671
                  "Content-type: text/html\r\n"
1672
                  "\r\n"
1673 5e567aae Diego Biurrun
                  "<html>\n"
1674
                  "<head><title>404 Not Found</title></head>\n"
1675
                  "<body>%s</body>\n"
1676
                  "</html>\n", msg);
1677 85f07f22 Fabrice Bellard
    /* prepare output buffer */
1678
    c->buffer_ptr = c->buffer;
1679
    c->buffer_end = q;
1680
    c->state = HTTPSTATE_SEND_HEADER;
1681
    return 0;
1682 dca21085 Stefano Sabatini
 send_status:
1683
    compute_status(c);
1684 85f07f22 Fabrice Bellard
    c->http_error = 200; /* horrible : we use this value to avoid
1685
                            going to the send data state */
1686
    c->state = HTTPSTATE_SEND_HEADER;
1687
    return 0;
1688
}
1689
1690 0c1a9eda Zdenek Kabelac
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1691 2ac887ba Philip Gladstone
{
1692
    static const char *suffix = " kMGTP";
1693
    const char *s;
1694
1695 611c5741 Alex Beregszaszi
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1696 2ac887ba Philip Gladstone
1697 4733abcb Måns Rullgård
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1698 2ac887ba Philip Gladstone
}
1699
1700 dca21085 Stefano Sabatini
static void compute_status(HTTPContext *c)
1701 85f07f22 Fabrice Bellard
{
1702
    HTTPContext *c1;
1703
    FFStream *stream;
1704 2effd274 Fabrice Bellard
    char *p;
1705 85f07f22 Fabrice Bellard
    time_t ti;
1706 2effd274 Fabrice Bellard
    int i, len;
1707 899681cd Björn Axelsson
    ByteIOContext *pb;
1708 cde25790 Philip Gladstone
1709 899681cd Björn Axelsson
    if (url_open_dyn_buf(&pb) < 0) {
1710 2effd274 Fabrice Bellard
        /* XXX: return an error ? */
1711 cde25790 Philip Gladstone
        c->buffer_ptr = c->buffer;
1712 2effd274 Fabrice Bellard
        c->buffer_end = c->buffer;
1713
        return;
1714 cde25790 Philip Gladstone
    }
1715 85f07f22 Fabrice Bellard
1716 2effd274 Fabrice Bellard
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1717
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1718
    url_fprintf(pb, "Pragma: no-cache\r\n");
1719
    url_fprintf(pb, "\r\n");
1720 115329f1 Diego Biurrun
1721 5e567aae Diego Biurrun
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1722 0679719d Erik Hovland
    if (c->stream->feed_filename[0])
1723 2effd274 Fabrice Bellard
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1724 5e567aae Diego Biurrun
    url_fprintf(pb, "</head>\n<body>");
1725
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1726 85f07f22 Fabrice Bellard
    /* format status */
1727 5e567aae Diego Biurrun
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1728
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1729
    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");
1730 85f07f22 Fabrice Bellard
    stream = first_stream;
1731
    while (stream != NULL) {
1732 42a63c6a Philip Gladstone
        char sfilename[1024];
1733
        char *eosf;
1734
1735 a6e14edd Philip Gladstone
        if (stream->feed != stream) {
1736 f7d78f36 Måns Rullgård
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1737 a6e14edd Philip Gladstone
            eosf = sfilename + strlen(sfilename);
1738
            if (eosf - sfilename >= 4) {
1739 611c5741 Alex Beregszaszi
                if (strcmp(eosf - 4, ".asf") == 0)
1740 a6e14edd Philip Gladstone
                    strcpy(eosf - 4, ".asx");
1741 611c5741 Alex Beregszaszi
                else if (strcmp(eosf - 3, ".rm") == 0)
1742 a6e14edd Philip Gladstone
                    strcpy(eosf - 3, ".ram");
1743 25e3e53d Luca Abeni
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1744 829ac53d Fabrice Bellard
                    /* generate a sample RTSP director if
1745
                       unicast. Generate an SDP redirector if
1746
                       multicast */
1747 2effd274 Fabrice Bellard
                    eosf = strrchr(sfilename, '.');
1748
                    if (!eosf)
1749
                        eosf = sfilename + strlen(sfilename);
1750 829ac53d Fabrice Bellard
                    if (stream->is_multicast)
1751
                        strcpy(eosf, ".sdp");
1752
                    else
1753
                        strcpy(eosf, ".rtsp");
1754 a6e14edd Philip Gladstone
                }
1755 42a63c6a Philip Gladstone
            }
1756 115329f1 Diego Biurrun
1757 5e567aae Diego Biurrun
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1758 a6e14edd Philip Gladstone
                         sfilename, stream->filename);
1759 2effd274 Fabrice Bellard
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1760 2ac887ba Philip Gladstone
                        stream->conns_served);
1761 2effd274 Fabrice Bellard
            fmt_bytecount(pb, stream->bytes_served);
1762 a6e14edd Philip Gladstone
            switch(stream->stream_type) {
1763 ace21da3 Baptiste Coudurier
            case STREAM_TYPE_LIVE: {
1764 a6e14edd Philip Gladstone
                    int audio_bit_rate = 0;
1765
                    int video_bit_rate = 0;
1766 58445440 Zdenek Kabelac
                    const char *audio_codec_name = "";
1767
                    const char *video_codec_name = "";
1768
                    const char *audio_codec_name_extra = "";
1769
                    const char *video_codec_name_extra = "";
1770 a6e14edd Philip Gladstone
1771
                    for(i=0;i<stream->nb_streams;i++) {
1772
                        AVStream *st = stream->streams[i];
1773 01f4895c Michael Niedermayer
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1774
                        switch(st->codec->codec_type) {
1775 a6e14edd Philip Gladstone
                        case CODEC_TYPE_AUDIO:
1776 01f4895c Michael Niedermayer
                            audio_bit_rate += st->codec->bit_rate;
1777 a6e14edd Philip Gladstone
                            if (codec) {
1778
                                if (*audio_codec_name)
1779
                                    audio_codec_name_extra = "...";
1780
                                audio_codec_name = codec->name;
1781
                            }
1782
                            break;
1783
                        case CODEC_TYPE_VIDEO:
1784 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1785 a6e14edd Philip Gladstone
                            if (codec) {
1786
                                if (*video_codec_name)
1787
                                    video_codec_name_extra = "...";
1788
                                video_codec_name = codec->name;
1789
                            }
1790
                            break;
1791 e240a0bb Fabrice Bellard
                        case CODEC_TYPE_DATA:
1792 01f4895c Michael Niedermayer
                            video_bit_rate += st->codec->bit_rate;
1793 e240a0bb Fabrice Bellard
                            break;
1794 a6e14edd Philip Gladstone
                        default:
1795 0f4e8165 Ronald S. Bultje
                            abort();
1796 79c4ea3c Philip Gladstone
                        }
1797 85f07f22 Fabrice Bellard
                    }
1798 5e567aae 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",
1799 a6e14edd Philip Gladstone
                                 stream->fmt->name,
1800 6edd6884 Fabrice Bellard
                                 stream->bandwidth,
1801 a6e14edd Philip Gladstone
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1802
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1803 611c5741 Alex Beregszaszi
                    if (stream->feed)
1804 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1805 611c5741 Alex Beregszaszi
                    else
1806 5e567aae Diego Biurrun
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1807 2effd274 Fabrice Bellard
                    url_fprintf(pb, "\n");
1808 85f07f22 Fabrice Bellard
                }
1809 a6e14edd Philip Gladstone
                break;
1810
            default:
1811 5e567aae Diego Biurrun
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1812 a6e14edd Philip Gladstone
                break;
1813 85f07f22 Fabrice Bellard
            }
1814
        }
1815
        stream = stream->next;
1816
    }
1817 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
1818 a6e14edd Philip Gladstone
1819
    stream = first_stream;
1820
    while (stream != NULL) {
1821
        if (stream->feed == stream) {
1822 2effd274 Fabrice Bellard
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1823 cde25790 Philip Gladstone
            if (stream->pid) {
1824 2effd274 Fabrice Bellard
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1825 cde25790 Philip Gladstone
1826 2effd274 Fabrice Bellard
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1827
                {
1828
                    FILE *pid_stat;
1829
                    char ps_cmd[64];
1830
1831
                    /* This is somewhat linux specific I guess */
1832 115329f1 Diego Biurrun
                    snprintf(ps_cmd, sizeof(ps_cmd),
1833
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1834 2effd274 Fabrice Bellard
                             stream->pid);
1835 115329f1 Diego Biurrun
1836 2effd274 Fabrice Bellard
                    pid_stat = popen(ps_cmd, "r");
1837
                    if (pid_stat) {
1838
                        char cpuperc[10];
1839
                        char cpuused[64];
1840 115329f1 Diego Biurrun
1841
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1842 2effd274 Fabrice Bellard
                                   cpuused) == 2) {
1843
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1844
                                         cpuperc, cpuused);
1845
                        }
1846
                        fclose(pid_stat);
1847 cde25790 Philip Gladstone
                    }
1848
                }
1849
#endif
1850
1851 2effd274 Fabrice Bellard
                url_fprintf(pb, "<p>");
1852 cde25790 Philip Gladstone
            }
1853 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");
1854 a6e14edd Philip Gladstone
1855
            for (i = 0; i < stream->nb_streams; i++) {
1856
                AVStream *st = stream->streams[i];
1857 01f4895c Michael Niedermayer
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1858 b29f97d1 Zdenek Kabelac
                const char *type = "unknown";
1859 b582f314 Philip Gladstone
                char parameters[64];
1860
1861
                parameters[0] = 0;
1862 a6e14edd Philip Gladstone
1863 01f4895c Michael Niedermayer
                switch(st->codec->codec_type) {
1864 a6e14edd Philip Gladstone
                case CODEC_TYPE_AUDIO:
1865
                    type = "audio";
1866 acdc8520 Alex Beregszaszi
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1867 a6e14edd Philip Gladstone
                    break;
1868
                case CODEC_TYPE_VIDEO:
1869
                    type = "video";
1870 01f4895c Michael Niedermayer
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1871
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1872 a6e14edd Philip Gladstone
                    break;
1873
                default:
1874 0f4e8165 Ronald S. Bultje
                    abort();
1875 a6e14edd Philip Gladstone
                }
1876 2effd274 Fabrice Bellard
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1877 01f4895c Michael Niedermayer
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1878 a6e14edd Philip Gladstone
            }
1879 2effd274 Fabrice Bellard
            url_fprintf(pb, "</table>\n");
1880 a6e14edd Philip Gladstone
1881 115329f1 Diego Biurrun
        }
1882 a6e14edd Philip Gladstone
        stream = stream->next;
1883
    }
1884 115329f1 Diego Biurrun
1885 85f07f22 Fabrice Bellard
    /* connection status */
1886 5e567aae Diego Biurrun
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1887 85f07f22 Fabrice Bellard
1888 5e567aae Diego Biurrun
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1889 85f07f22 Fabrice Bellard
                 nb_connections, nb_max_connections);
1890
1891 5e567aae Diego Biurrun
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1892 6edd6884 Fabrice Bellard
                 current_bandwidth, max_bandwidth);
1893 42a63c6a Philip Gladstone
1894 5e567aae Diego Biurrun
    url_fprintf(pb, "<table>\n");
1895
    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");
1896 85f07f22 Fabrice Bellard
    c1 = first_http_ctx;
1897
    i = 0;
1898 2effd274 Fabrice Bellard
    while (c1 != NULL) {
1899 cde25790 Philip Gladstone
        int bitrate;
1900
        int j;
1901
1902
        bitrate = 0;
1903 2effd274 Fabrice Bellard
        if (c1->stream) {
1904
            for (j = 0; j < c1->stream->nb_streams; j++) {
1905 2d563d2f Alex Beregszaszi
                if (!c1->stream->feed)
1906 01f4895c Michael Niedermayer
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1907 2d563d2f Alex Beregszaszi
                else if (c1->feed_streams[j] >= 0)
1908
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1909 cde25790 Philip Gladstone
            }
1910
        }
1911
1912 85f07f22 Fabrice Bellard
        i++;
1913
        p = inet_ntoa(c1->from_addr.sin_addr);
1914 5e567aae Diego Biurrun
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1915 115329f1 Diego Biurrun
                    i,
1916
                    c1->stream ? c1->stream->filename : "",
1917 2effd274 Fabrice Bellard
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1918 115329f1 Diego Biurrun
                    p,
1919 2effd274 Fabrice Bellard
                    c1->protocol,
1920
                    http_state[c1->state]);
1921
        fmt_bytecount(pb, bitrate);
1922
        url_fprintf(pb, "<td align=right>");
1923
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1924
        url_fprintf(pb, "<td align=right>");
1925
        fmt_bytecount(pb, c1->data_count);
1926
        url_fprintf(pb, "\n");
1927 85f07f22 Fabrice Bellard
        c1 = c1->next;
1928
    }
1929 5e567aae Diego Biurrun
    url_fprintf(pb, "</table>\n");
1930 115329f1 Diego Biurrun
1931 85f07f22 Fabrice Bellard
    /* date */
1932
    ti = time(NULL);
1933
    p = ctime(&ti);
1934 5e567aae Diego Biurrun
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1935
    url_fprintf(pb, "</body>\n</html>\n");
1936 85f07f22 Fabrice Bellard
1937 2effd274 Fabrice Bellard
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1938
    c->buffer_ptr = c->pb_buffer;
1939
    c->buffer_end = c->pb_buffer + len;
1940 85f07f22 Fabrice Bellard
}
1941
1942 2effd274 Fabrice Bellard
/* check if the parser needs to be opened for stream i */
1943
static void open_parser(AVFormatContext *s, int i)
1944 85f07f22 Fabrice Bellard
{
1945 2effd274 Fabrice Bellard
    AVStream *st = s->streams[i];
1946
    AVCodec *codec;
1947 31def229 Philip Gladstone
1948 01f4895c Michael Niedermayer
    if (!st->codec->codec) {
1949
        codec = avcodec_find_decoder(st->codec->codec_id);
1950 2effd274 Fabrice Bellard
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1951 01f4895c Michael Niedermayer
            st->codec->parse_only = 1;
1952 611c5741 Alex Beregszaszi
            if (avcodec_open(st->codec, codec) < 0)
1953 01f4895c Michael Niedermayer
                st->codec->parse_only = 0;
1954 cde25790 Philip Gladstone
        }
1955
    }
1956 85f07f22 Fabrice Bellard
}
1957
1958
static int open_input_stream(HTTPContext *c, const char *info)
1959
{
1960
    char buf[128];
1961
    char input_filename[1024];
1962
    AVFormatContext *s;
1963 c351cc7f Baptiste Coudurier
    int buf_size, i, ret;
1964 0c1a9eda Zdenek Kabelac
    int64_t stream_pos;
1965 85f07f22 Fabrice Bellard
1966
    /* find file name */
1967
    if (c->stream->feed) {
1968
        strcpy(input_filename, c->stream->feed->feed_filename);
1969
        buf_size = FFM_PACKET_SIZE;
1970
        /* compute position (absolute time) */
1971 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1972 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 0);
1973 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1974
                return -1;
1975 ace21da3 Baptiste Coudurier
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1976 f747e6d3 Philip Gladstone
            int prebuffer = strtol(buf, 0, 10);
1977 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1978 611c5741 Alex Beregszaszi
        } else
1979 0c1a9eda Zdenek Kabelac
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1980 85f07f22 Fabrice Bellard
    } else {
1981
        strcpy(input_filename, c->stream->feed_filename);
1982
        buf_size = 0;
1983
        /* compute position (relative time) */
1984 ace21da3 Baptiste Coudurier
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1985 85f07f22 Fabrice Bellard
            stream_pos = parse_date(buf, 1);
1986 f9436161 Stefano Sabatini
            if (stream_pos == INT64_MIN)
1987
                return -1;
1988 ace21da3 Baptiste Coudurier
        } else
1989 85f07f22 Fabrice Bellard
            stream_pos = 0;
1990
    }
1991
    if (input_filename[0] == '\0')
1992
        return -1;
1993
1994
    /* open stream */
1995 c351cc7f Baptiste Coudurier
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1996
                                  buf_size, c->stream->ap_in)) < 0) {
1997
        http_log("could not open %s: %d\n", input_filename, ret);
1998 85f07f22 Fabrice Bellard
        return -1;
1999 2effd274 Fabrice Bellard
    }
2000 9dc0bc3d Luca Abeni
    s->flags |= AVFMT_FLAG_GENPTS;
2001 85f07f22 Fabrice Bellard
    c->fmt_in = s;
2002 85fe4ae0 Baptiste Coudurier
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2003 20f93c3c Baptiste Coudurier
        http_log("Could not find stream info '%s'\n", input_filename);
2004
        av_close_input_file(s);
2005
        return -1;
2006
    }
2007 115329f1 Diego Biurrun
2008 2effd274 Fabrice Bellard
    /* open each parser */
2009
    for(i=0;i<s->nb_streams;i++)
2010
        open_parser(s, i);
2011
2012
    /* choose stream as clock source (we favorize video stream if
2013
       present) for packet sending */
2014
    c->pts_stream_index = 0;
2015
    for(i=0;i<c->stream->nb_streams;i++) {
2016 115329f1 Diego Biurrun
        if (c->pts_stream_index == 0 &&
2017 01f4895c Michael Niedermayer
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2018 2effd274 Fabrice Bellard
            c->pts_stream_index = i;
2019
        }
2020
    }
2021 85f07f22 Fabrice Bellard
2022 e8d27bc3 Philip Gladstone
#if 1
2023 611c5741 Alex Beregszaszi
    if (c->fmt_in->iformat->read_seek)
2024 60a04f7f Baptiste Coudurier
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2025 e240a0bb Fabrice Bellard
#endif
2026 2effd274 Fabrice Bellard
    /* set the start time (needed for maxtime and RTP packet timing) */
2027
    c->start_time = cur_time;
2028
    c->first_pts = AV_NOPTS_VALUE;
2029 85f07f22 Fabrice Bellard
    return 0;
2030
}
2031
2032 e240a0bb Fabrice Bellard
/* return the server clock (in us) */
2033
static int64_t get_server_clock(HTTPContext *c)
2034 2effd274 Fabrice Bellard
{
2035 e240a0bb Fabrice Bellard
    /* compute current pts value from system time */
2036 c3f58185 Alex Beregszaszi
    return (cur_time - c->start_time) * 1000;
2037 2effd274 Fabrice Bellard
}
2038
2039 e240a0bb Fabrice Bellard
/* return the estimated time at which the current packet must be sent
2040
   (in us) */
2041
static int64_t get_packet_send_clock(HTTPContext *c)
2042 2effd274 Fabrice Bellard
{
2043 e240a0bb Fabrice Bellard
    int bytes_left, bytes_sent, frame_bytes;
2044 115329f1 Diego Biurrun
2045 e240a0bb Fabrice Bellard
    frame_bytes = c->cur_frame_bytes;
2046 611c5741 Alex Beregszaszi
    if (frame_bytes <= 0)
2047 e240a0bb Fabrice Bellard
        return c->cur_pts;
2048 611c5741 Alex Beregszaszi
    else {
2049 e240a0bb Fabrice Bellard
        bytes_left = c->buffer_end - c->buffer_ptr;
2050
        bytes_sent = frame_bytes - bytes_left;
2051
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2052 2effd274 Fabrice Bellard
    }
2053
}
2054
2055
2056
static int http_prepare_data(HTTPContext *c)
2057
{
2058
    int i, len, ret;
2059
    AVFormatContext *ctx;
2060
2061 bc351386 Fabrice Bellard
    av_freep(&c->pb_buffer);
2062 2effd274 Fabrice Bellard
    switch(c->state) {
2063
    case HTTPSTATE_SEND_DATA_HEADER:
2064
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2065 5ee999b8 Aurelien Jacobs
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2066
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2067
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2068
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2069 2effd274 Fabrice Bellard
2070 3d9cc27d Baptiste Coudurier
        for(i=0;i<c->stream->nb_streams;i++) {
2071 2effd274 Fabrice Bellard
            AVStream *st;
2072 bb270c08 Diego Biurrun
            AVStream *src;
2073 2effd274 Fabrice Bellard
            st = av_mallocz(sizeof(AVStream));
2074
            c->fmt_ctx.streams[i] = st;
2075
            /* if file or feed, then just take streams from FFStream struct */
2076 115329f1 Diego Biurrun
            if (!c->stream->feed ||
2077 2effd274 Fabrice Bellard
                c->stream->feed == c->stream)
2078 7c054ea7 Philip Gladstone
                src = c->stream->streams[i];
2079 2effd274 Fabrice Bellard
            else
2080 7c054ea7 Philip Gladstone
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2081
2082 bb270c08 Diego Biurrun
            *st = *src;
2083
            st->priv_data = 0;
2084 01f4895c Michael Niedermayer
            st->codec->frame_number = 0; /* XXX: should be done in
2085 2effd274 Fabrice Bellard
                                           AVStream, not in codec */
2086
        }
2087 3d9cc27d Baptiste Coudurier
        /* set output format parameters */
2088
        c->fmt_ctx.oformat = c->stream->fmt;
2089
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2090
2091 2effd274 Fabrice Bellard
        c->got_key_frame = 0;
2092
2093
        /* prepare header and save header data in a stream */
2094
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2095
            /* XXX: potential leak */
2096
            return -1;
2097
        }
2098 899681cd Björn Axelsson
        c->fmt_ctx.pb->is_streamed = 1;
2099 2effd274 Fabrice Bellard
2100 8aae202e Baptiste Coudurier
        /*
2101
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2102
         * Default value from FFmpeg
2103
         * Try to set it use configuration option
2104
         */
2105
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2106
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2107
2108 3c27199b Fabrice Bellard
        av_set_parameters(&c->fmt_ctx, NULL);
2109 929a9b75 Baptiste Coudurier
        if (av_write_header(&c->fmt_ctx) < 0) {
2110
            http_log("Error writing output header\n");
2111 f75cdda7 Alex Beregszaszi
            return -1;
2112 929a9b75 Baptiste Coudurier
        }
2113 2effd274 Fabrice Bellard
2114 899681cd Björn Axelsson
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2115 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2116
        c->buffer_end = c->pb_buffer + len;
2117
2118
        c->state = HTTPSTATE_SEND_DATA;
2119 85f07f22 Fabrice Bellard
        c->last_packet_sent = 0;
2120
        break;
2121
    case HTTPSTATE_SEND_DATA:
2122
        /* find a new packet */
2123 3b371676 Baptiste Coudurier
        /* read a packet from the input stream */
2124
        if (c->stream->feed)
2125
            ffm_set_write_index(c->fmt_in,
2126
                                c->stream->feed->feed_write_index,
2127
                                c->stream->feed->feed_size);
2128
2129
        if (c->stream->max_time &&
2130
            c->stream->max_time + c->start_time - cur_time < 0)
2131
            /* We have timed out */
2132
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2133
        else {
2134
            AVPacket pkt;
2135
        redo:
2136
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2137
                if (c->stream->feed && c->stream->feed->feed_opened) {
2138
                    /* if coming from feed, it means we reached the end of the
2139
                       ffm file, so must wait for more data */
2140
                    c->state = HTTPSTATE_WAIT_FEED;
2141
                    return 1; /* state changed */
2142 2effd274 Fabrice Bellard
                } else {
2143 3b371676 Baptiste Coudurier
                    if (c->stream->loop) {
2144
                        av_close_input_file(c->fmt_in);
2145
                        c->fmt_in = NULL;
2146
                        if (open_input_stream(c, "") < 0)
2147
                            goto no_loop;
2148
                        goto redo;
2149
                    } else {
2150
                    no_loop:
2151
                        /* must send trailer now because eof or error */
2152
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2153 1bc1cfdd Giancarlo Formicuccia
                    }
2154 3b371676 Baptiste Coudurier
                }
2155
            } else {
2156 084a8912 Baptiste Coudurier
                int source_index = pkt.stream_index;
2157 3b371676 Baptiste Coudurier
                /* update first pts if needed */
2158
                if (c->first_pts == AV_NOPTS_VALUE) {
2159
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2160
                    c->start_time = cur_time;
2161
                }
2162
                /* send it to the appropriate stream */
2163
                if (c->stream->feed) {
2164
                    /* if coming from a feed, select the right stream */
2165
                    if (c->switch_pending) {
2166
                        c->switch_pending = 0;
2167 cde25790 Philip Gladstone
                        for(i=0;i<c->stream->nb_streams;i++) {
2168 3b371676 Baptiste Coudurier
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2169 611c5741 Alex Beregszaszi
                                if (pkt.flags & PKT_FLAG_KEY)
2170 3b371676 Baptiste Coudurier
                                    do_switch_stream(c, i);
2171
                            if (c->switch_feed_streams[i] >= 0)
2172
                                c->switch_pending = 1;
2173 cde25790 Philip Gladstone
                        }
2174 3b371676 Baptiste Coudurier
                    }
2175
                    for(i=0;i<c->stream->nb_streams;i++) {
2176
                        if (c->feed_streams[i] == pkt.stream_index) {
2177 78728064 Baptiste Coudurier
                            AVStream *st = c->fmt_in->streams[source_index];
2178 3b371676 Baptiste Coudurier
                            pkt.stream_index = i;
2179 180b7026 Baptiste Coudurier
                            if (pkt.flags & PKT_FLAG_KEY &&
2180
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2181
                                 c->stream->nb_streams == 1))
2182 0332f549 Baptiste Coudurier
                                c->got_key_frame = 1;
2183
                            if (!c->stream->send_on_key || c->got_key_frame)
2184 3b371676 Baptiste Coudurier
                                goto send_it;
2185
                        }
2186
                    }
2187
                } else {
2188
                    AVCodecContext *codec;
2189 dc3a6a36 Baptiste Coudurier
                    AVStream *ist, *ost;
2190
                send_it:
2191
                    ist = c->fmt_in->streams[source_index];
2192 3b371676 Baptiste Coudurier
                    /* specific handling for RTP: we use several
2193
                       output stream (one for each RTP
2194
                       connection). XXX: need more abstract handling */
2195
                    if (c->is_packetized) {
2196
                        /* compute send time and duration */
2197 8f56ccca Baptiste Coudurier
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2198
                        if (ist->start_time != AV_NOPTS_VALUE)
2199
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2200
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2201 3b371676 Baptiste Coudurier
                        /* find RTP context */
2202
                        c->packet_stream_index = pkt.stream_index;
2203
                        ctx = c->rtp_ctx[c->packet_stream_index];
2204
                        if(!ctx) {
2205 8a0b55ff Baptiste Coudurier
                            av_free_packet(&pkt);
2206 3b371676 Baptiste Coudurier
                            break;
2207 8a0b55ff Baptiste Coudurier
                        }
2208 3b371676 Baptiste Coudurier
                        codec = ctx->streams[0]->codec;
2209
                        /* only one stream per RTP connection */
2210
                        pkt.stream_index = 0;
2211
                    } else {
2212
                        ctx = &c->fmt_ctx;
2213
                        /* Fudge here */
2214 3ab29d8e Baptiste Coudurier
                        codec = ctx->streams[pkt.stream_index]->codec;
2215 3b371676 Baptiste Coudurier
                    }
2216
2217
                    if (c->is_packetized) {
2218
                        int max_packet_size;
2219 90abbdba Ronald S. Bultje
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2220 3b371676 Baptiste Coudurier
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2221
                        else
2222
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2223
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2224
                    } else {
2225
                        ret = url_open_dyn_buf(&ctx->pb);
2226
                    }
2227
                    if (ret < 0) {
2228
                        /* XXX: potential leak */
2229
                        return -1;
2230
                    }
2231 3ab29d8e Baptiste Coudurier
                    ost = ctx->streams[pkt.stream_index];
2232
2233 b0675954 Baptiste Coudurier
                    ctx->pb->is_streamed = 1;
2234 3b371676 Baptiste Coudurier
                    if (pkt.dts != AV_NOPTS_VALUE)
2235 d80904cc Baptiste Coudurier
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2236 3b371676 Baptiste Coudurier
                    if (pkt.pts != AV_NOPTS_VALUE)
2237 d80904cc Baptiste Coudurier
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2238
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2239 3766ed72 Baptiste Coudurier
                    if (av_write_frame(ctx, &pkt) < 0) {
2240
                        http_log("Error writing frame to output\n");
2241 3b371676 Baptiste Coudurier
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2242 3766ed72 Baptiste Coudurier
                    }
2243 3b371676 Baptiste Coudurier
2244
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2245
                    c->cur_frame_bytes = len;
2246
                    c->buffer_ptr = c->pb_buffer;
2247
                    c->buffer_end = c->pb_buffer + len;
2248
2249
                    codec->frame_number++;
2250
                    if (len == 0) {
2251
                        av_free_packet(&pkt);
2252
                        goto redo;
2253 f747e6d3 Philip Gladstone
                    }
2254 85f07f22 Fabrice Bellard
                }
2255 3b371676 Baptiste Coudurier
                av_free_packet(&pkt);
2256 85f07f22 Fabrice Bellard
            }
2257 3b371676 Baptiste Coudurier
        }
2258 85f07f22 Fabrice Bellard
        break;
2259
    default:
2260
    case HTTPSTATE_SEND_DATA_TRAILER:
2261
        /* last packet test ? */
2262 2effd274 Fabrice Bellard
        if (c->last_packet_sent || c->is_packetized)
2263 85f07f22 Fabrice Bellard
            return -1;
2264 2effd274 Fabrice Bellard
        ctx = &c->fmt_ctx;
2265 85f07f22 Fabrice Bellard
        /* prepare header */
2266 2effd274 Fabrice Bellard
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2267
            /* XXX: potential leak */
2268
            return -1;
2269
        }
2270 58bd615f Baptiste Coudurier
        c->fmt_ctx.pb->is_streamed = 1;
2271 2effd274 Fabrice Bellard
        av_write_trailer(ctx);
2272 899681cd Björn Axelsson
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2273 2effd274 Fabrice Bellard
        c->buffer_ptr = c->pb_buffer;
2274
        c->buffer_end = c->pb_buffer + len;
2275
2276 85f07f22 Fabrice Bellard
        c->last_packet_sent = 1;
2277
        break;
2278
    }
2279
    return 0;
2280
}
2281
2282
/* should convert the format at the same time */
2283 bc351386 Fabrice Bellard
/* send data starting at c->buffer_ptr to the output connection
2284
   (either UDP or TCP connection) */
2285 5eb765ef Philip Gladstone
static int http_send_data(HTTPContext *c)
2286 85f07f22 Fabrice Bellard
{
2287 e240a0bb Fabrice Bellard
    int len, ret;
2288 85f07f22 Fabrice Bellard
2289 bc351386 Fabrice Bellard
    for(;;) {
2290
        if (c->buffer_ptr >= c->buffer_end) {
2291
            ret = http_prepare_data(c);
2292
            if (ret < 0)
2293
                return -1;
2294 611c5741 Alex Beregszaszi
            else if (ret != 0)
2295 bc351386 Fabrice Bellard
                /* state change requested */
2296
                break;
2297 2effd274 Fabrice Bellard
        } else {
2298 bc351386 Fabrice Bellard
            if (c->is_packetized) {
2299
                /* RTP data output */
2300
                len = c->buffer_end - c->buffer_ptr;
2301
                if (len < 4) {
2302
                    /* fail safe - should never happen */
2303
                fail1:
2304
                    c->buffer_ptr = c->buffer_end;
2305 2effd274 Fabrice Bellard
                    return 0;
2306
                }
2307 bc351386 Fabrice Bellard
                len = (c->buffer_ptr[0] << 24) |
2308
                    (c->buffer_ptr[1] << 16) |
2309
                    (c->buffer_ptr[2] << 8) |
2310
                    (c->buffer_ptr[3]);
2311
                if (len > (c->buffer_end - c->buffer_ptr))
2312
                    goto fail1;
2313 e240a0bb Fabrice Bellard
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2314
                    /* nothing to send yet: we can wait */
2315
                    return 0;
2316
                }
2317
2318
                c->data_count += len;
2319
                update_datarate(&c->datarate, c->data_count);
2320
                if (c->stream)
2321
                    c->stream->bytes_served += len;
2322
2323 90abbdba Ronald S. Bultje
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2324 bc351386 Fabrice Bellard
                    /* RTP packets are sent inside the RTSP TCP connection */
2325 899681cd Björn Axelsson
                    ByteIOContext *pb;
2326 bc351386 Fabrice Bellard
                    int interleaved_index, size;
2327
                    uint8_t header[4];
2328
                    HTTPContext *rtsp_c;
2329 115329f1 Diego Biurrun
2330 bc351386 Fabrice Bellard
                    rtsp_c = c->rtsp_c;
2331
                    /* if no RTSP connection left, error */
2332
                    if (!rtsp_c)
2333
                        return -1;
2334
                    /* if already sending something, then wait. */
2335 611c5741 Alex Beregszaszi
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2336 bc351386 Fabrice Bellard
                        break;
2337 899681cd Björn Axelsson
                    if (url_open_dyn_buf(&pb) < 0)
2338 bc351386 Fabrice Bellard
                        goto fail1;
2339
                    interleaved_index = c->packet_stream_index * 2;
2340
                    /* RTCP packets are sent at odd indexes */
2341
                    if (c->buffer_ptr[1] == 200)
2342
                        interleaved_index++;
2343
                    /* write RTSP TCP header */
2344
                    header[0] = '$';
2345
                    header[1] = interleaved_index;
2346
                    header[2] = len >> 8;
2347
                    header[3] = len;
2348
                    put_buffer(pb, header, 4);
2349
                    /* write RTP packet data */
2350
                    c->buffer_ptr += 4;
2351
                    put_buffer(pb, c->buffer_ptr, len);
2352
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2353
                    /* prepare asynchronous TCP sending */
2354
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2355
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2356 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2357 115329f1 Diego Biurrun
2358 e240a0bb Fabrice Bellard
                    /* send everything we can NOW */
2359 c60202df Alex Beregszaszi
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2360
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2361 611c5741 Alex Beregszaszi
                    if (len > 0)
2362 e240a0bb Fabrice Bellard
                        rtsp_c->packet_buffer_ptr += len;
2363
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2364
                        /* if we could not send all the data, we will
2365
                           send it later, so a new state is needed to
2366
                           "lock" the RTSP TCP connection */
2367
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2368
                        break;
2369 611c5741 Alex Beregszaszi
                    } else
2370 e240a0bb Fabrice Bellard
                        /* all data has been sent */
2371
                        av_freep(&c->packet_buffer);
2372
                } else {
2373
                    /* send RTP packet directly in UDP */
2374 bc351386 Fabrice Bellard
                    c->buffer_ptr += 4;
2375 115329f1 Diego Biurrun
                    url_write(c->rtp_handles[c->packet_stream_index],
2376 bc351386 Fabrice Bellard
                              c->buffer_ptr, len);
2377 e240a0bb Fabrice Bellard
                    c->buffer_ptr += len;
2378
                    /* here we continue as we can send several packets per 10 ms slot */
2379 bc351386 Fabrice Bellard
                }
2380
            } else {
2381
                /* TCP data output */
2382 c60202df Alex Beregszaszi
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2383 bc351386 Fabrice Bellard
                if (len < 0) {
2384 8da4034f Alex Beregszaszi
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2385 611c5741 Alex Beregszaszi
                        ff_neterrno() != FF_NETERROR(EINTR))
2386 bc351386 Fabrice Bellard
                        /* error : close connection */
2387
                        return -1;
2388 611c5741 Alex Beregszaszi
                    else
2389 bc351386 Fabrice Bellard
                        return 0;
2390 611c5741 Alex Beregszaszi
                } else
2391 bc351386 Fabrice Bellard
                    c->buffer_ptr += len;
2392 611c5741 Alex Beregszaszi
2393 e240a0bb Fabrice Bellard
                c->data_count += len;
2394
                update_datarate(&c->datarate, c->data_count);
2395
                if (c->stream)
2396
                    c->stream->bytes_served += len;
2397
                break;
2398 2effd274 Fabrice Bellard
            }
2399 85f07f22 Fabrice Bellard
        }
2400 bc351386 Fabrice Bellard
    } /* for(;;) */
2401 85f07f22 Fabrice Bellard
    return 0;
2402
}
2403
2404
static int http_start_receive_data(HTTPContext *c)
2405
{
2406
    int fd;
2407
2408
    if (c->stream->feed_opened)
2409
        return -1;
2410
2411 e322ea48 Philip Gladstone
    /* Don't permit writing to this one */
2412
    if (c->stream->readonly)
2413
        return -1;
2414
2415 85f07f22 Fabrice Bellard
    /* open feed */
2416
    fd = open(c->stream->feed_filename, O_RDWR);
2417 929a9b75 Baptiste Coudurier
    if (fd < 0) {
2418
        http_log("Error opening feeder file: %s\n", strerror(errno));
2419 85f07f22 Fabrice Bellard
        return -1;
2420 929a9b75 Baptiste Coudurier
    }
2421 85f07f22 Fabrice Bellard
    c->feed_fd = fd;
2422 115329f1 Diego Biurrun
2423 861ec13a Baptiste Coudurier
    if (c->stream->truncate) {
2424
        /* truncate feed file */
2425
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2426
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2427
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2428
    } else {
2429 1f611549 Baptiste Coudurier
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2430
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2431
            return -1;
2432
        }
2433 861ec13a Baptiste Coudurier
    }
2434
2435 7e24aa0c Baptiste Coudurier
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2436 85f07f22 Fabrice Bellard
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2437
    lseek(fd, 0, SEEK_SET);
2438
2439
    /* init buffer input */
2440
    c->buffer_ptr = c->buffer;
2441
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2442
    c->stream->feed_opened = 1;
2443
    return 0;
2444
}
2445 115329f1 Diego Biurrun
2446 85f07f22 Fabrice Bellard
static int http_receive_data(HTTPContext *c)
2447
{
2448
    HTTPContext *c1;
2449
2450 a6e14edd Philip Gladstone
    if (c->buffer_end > c->buffer_ptr) {
2451
        int len;
2452
2453 c60202df Alex Beregszaszi
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2454 a6e14edd Philip Gladstone
        if (len < 0) {
2455 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2456 611c5741 Alex Beregszaszi
                ff_neterrno() != FF_NETERROR(EINTR))
2457 a6e14edd Philip Gladstone
                /* error : close connection */
2458
                goto fail;
2459 611c5741 Alex Beregszaszi
        } else if (len == 0)
2460 a6e14edd Philip Gladstone
            /* end of connection : close it */
2461
            goto fail;
2462 611c5741 Alex Beregszaszi
        else {
2463 a6e14edd Philip Gladstone
            c->buffer_ptr += len;
2464
            c->data_count += len;
2465 5eb765ef Philip Gladstone
            update_datarate(&c->datarate, c->data_count);
2466 a6e14edd Philip Gladstone
        }
2467
    }
2468
2469 d445a7e9 Philip Gladstone
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2470
        if (c->buffer[0] != 'f' ||
2471
            c->buffer[1] != 'm') {
2472
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2473
            goto fail;
2474
        }
2475
    }
2476
2477 85f07f22 Fabrice Bellard
    if (c->buffer_ptr >= c->buffer_end) {
2478 f747e6d3 Philip Gladstone
        FFStream *feed = c->stream;
2479 85f07f22 Fabrice Bellard
        /* a packet has been received : write it in the store, except
2480
           if header */
2481
        if (c->data_count > FFM_PACKET_SIZE) {
2482 115329f1 Diego Biurrun
2483 949b1a13 Steve L'Homme
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2484 85f07f22 Fabrice Bellard
            /* XXX: use llseek or url_seek */
2485
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2486 929a9b75 Baptiste Coudurier
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2487
                http_log("Error writing to feed file: %s\n", strerror(errno));
2488
                goto fail;
2489
            }
2490 115329f1 Diego Biurrun
2491 85f07f22 Fabrice Bellard
            feed->feed_write_index += FFM_PACKET_SIZE;
2492
            /* update file size */
2493
            if (feed->feed_write_index > c->stream->feed_size)
2494
                feed->feed_size = feed->feed_write_index;
2495
2496
            /* handle wrap around if max file size reached */
2497 6b0bdc75 Alex Beregszaszi
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2498 85f07f22 Fabrice Bellard
                feed->feed_write_index = FFM_PACKET_SIZE;
2499
2500
            /* write index */
2501 2779cdad Patrik Kullman
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2502
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2503
                goto fail;
2504
            }
2505 85f07f22 Fabrice Bellard
2506
            /* wake up any waiting connections */
2507
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2508 115329f1 Diego Biurrun
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2509 611c5741 Alex Beregszaszi
                    c1->stream->feed == c->stream->feed)
2510 85f07f22 Fabrice Bellard
                    c1->state = HTTPSTATE_SEND_DATA;
2511
            }
2512 f747e6d3 Philip Gladstone
        } else {
2513
            /* We have a header in our hands that contains useful data */
2514 f2972c8c Baptiste Coudurier
            AVFormatContext *s = NULL;
2515
            ByteIOContext *pb;
2516 bd7cf6ad Fabrice Bellard
            AVInputFormat *fmt_in;
2517 f747e6d3 Philip Gladstone
            int i;
2518
2519 bd7cf6ad Fabrice Bellard
            /* use feed output format name to find corresponding input format */
2520
            fmt_in = av_find_input_format(feed->fmt->name);
2521
            if (!fmt_in)
2522
                goto fail;
2523
2524 697efa36 Baptiste Coudurier
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2525
            pb->is_streamed = 1;
2526
2527 e6f0deab Baptiste Coudurier
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2528
                av_free(pb);
2529
                goto fail;
2530
            }
2531 f747e6d3 Philip Gladstone
2532
            /* Now we have the actual streams */
2533 f2972c8c Baptiste Coudurier
            if (s->nb_streams != feed->nb_streams) {
2534
                av_close_input_stream(s);
2535 86771c68 Baptiste Coudurier
                av_free(pb);
2536 77553ae3 Baptiste Coudurier
                http_log("Feed '%s' stream number does not match registered feed\n",
2537
                         c->stream->feed_filename);
2538 f747e6d3 Philip Gladstone
                goto fail;
2539
            }
2540 f2972c8c Baptiste Coudurier
2541 cb51aef1 Baptiste Coudurier
            for (i = 0; i < s->nb_streams; i++) {
2542
                AVStream *fst = feed->streams[i];
2543
                AVStream *st = s->streams[i];
2544
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2545
                if (fst->codec->extradata_size) {
2546
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2547
                    if (!fst->codec->extradata)
2548
                        goto fail;
2549
                    memcpy(fst->codec->extradata, st->codec->extradata,
2550
                           fst->codec->extradata_size);
2551
                }
2552
            }
2553 f2972c8c Baptiste Coudurier
2554
            av_close_input_stream(s);
2555 86771c68 Baptiste Coudurier
            av_free(pb);
2556 85f07f22 Fabrice Bellard
        }
2557
        c->buffer_ptr = c->buffer;
2558
    }
2559
2560
    return 0;
2561
 fail:
2562
    c->stream->feed_opened = 0;
2563
    close(c->feed_fd);
2564 c1593d0e Baptiste Coudurier
    /* wake up any waiting connections to stop waiting for feed */
2565
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2566
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2567
            c1->stream->feed == c->stream->feed)
2568
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2569
    }
2570 85f07f22 Fabrice Bellard
    return -1;
2571
}
2572
2573 2effd274 Fabrice Bellard
/********************************************************************/
2574
/* RTSP handling */
2575
2576
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2577
{
2578
    const char *str;
2579
    time_t ti;
2580
    char *p;
2581
    char buf2[32];
2582
2583
    switch(error_number) {
2584 7e665cd3 Luca Abeni
    case RTSP_STATUS_OK:
2585
        str = "OK";
2586
        break;
2587
    case RTSP_STATUS_METHOD:
2588
        str = "Method Not Allowed";
2589
        break;
2590
    case RTSP_STATUS_BANDWIDTH:
2591
        str = "Not Enough Bandwidth";
2592
        break;
2593
    case RTSP_STATUS_SESSION:
2594
        str = "Session Not Found";
2595
        break;
2596
    case RTSP_STATUS_STATE:
2597
        str = "Method Not Valid in This State";
2598
        break;
2599
    case RTSP_STATUS_AGGREGATE:
2600
        str = "Aggregate operation not allowed";
2601
        break;
2602
    case RTSP_STATUS_ONLY_AGGREGATE:
2603
        str = "Only aggregate operation allowed";
2604
        break;
2605
    case RTSP_STATUS_TRANSPORT:
2606
        str = "Unsupported transport";
2607
        break;
2608
    case RTSP_STATUS_INTERNAL:
2609
        str = "Internal Server Error";
2610
        break;
2611
    case RTSP_STATUS_SERVICE:
2612
        str = "Service Unavailable";
2613
        break;
2614
    case RTSP_STATUS_VERSION:
2615
        str = "RTSP Version not supported";
2616
        break;
2617 2effd274 Fabrice Bellard
    default:
2618
        str = "Unknown Error";
2619
        break;
2620
    }
2621 115329f1 Diego Biurrun
2622 2effd274 Fabrice Bellard
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2623
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2624
2625
    /* output GMT time */
2626
    ti = time(NULL);
2627
    p = ctime(&ti);
2628
    strcpy(buf2, p);
2629
    p = buf2 + strlen(p) - 1;
2630
    if (*p == '\n')
2631
        *p = '\0';
2632
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2633
}
2634
2635
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2636
{
2637
    rtsp_reply_header(c, error_number);
2638
    url_fprintf(c->pb, "\r\n");
2639
}
2640
2641
static int rtsp_parse_request(HTTPContext *c)
2642
{
2643
    const char *p, *p1, *p2;
2644
    char cmd[32];
2645
    char url[1024];
2646
    char protocol[32];
2647
    char line[1024];
2648
    int len;
2649 a9e534d5 Ronald S. Bultje
    RTSPMessageHeader header1, *header = &header1;
2650 115329f1 Diego Biurrun
2651 2effd274 Fabrice Bellard
    c->buffer_ptr[0] = '\0';
2652
    p = c->buffer;
2653 115329f1 Diego Biurrun
2654 2effd274 Fabrice Bellard
    get_word(cmd, sizeof(cmd), &p);
2655
    get_word(url, sizeof(url), &p);
2656
    get_word(protocol, sizeof(protocol), &p);
2657
2658 f7d78f36 Måns Rullgård
    av_strlcpy(c->method, cmd, sizeof(c->method));
2659
    av_strlcpy(c->url, url, sizeof(c->url));
2660
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2661 2effd274 Fabrice Bellard
2662 899681cd Björn Axelsson
    if (url_open_dyn_buf(&c->pb) < 0) {
2663 2effd274 Fabrice Bellard
        /* XXX: cannot do more */
2664
        c->pb = NULL; /* safety */
2665
        return -1;
2666
    }
2667