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