Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 1d6eeebe

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

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

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