Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ dc032f33

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