Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 4869f47e

History | View | Annotate | Download (150 KB)

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

1829 85f07f22 Fabrice Bellard
        /* feed status */
1830
        stream = first_feed;
1831
        while (stream != NULL) {
1832 2effd274 Fabrice Bellard
            url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1833
            url_fprintf(pb, "<TABLE>\n");
1834
            url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1835 85f07f22 Fabrice Bellard
            for(i=0;i<stream->nb_streams;i++) {
1836
                AVStream *st = stream->streams[i];
1837
                FeedData *fdata = st->priv_data;
1838 01f4895c Michael Niedermayer
                enc = st->codec;
1839 115329f1 Diego Biurrun

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